packlight-cli 0.0.0-stage → 0.1.1
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 +25 -0
- package/LICENSE +21 -0
- package/README.md +72 -2
- package/dist/adapters/claude-code/inventory.d.ts +48 -0
- package/dist/adapters/claude-code/inventory.js +449 -0
- package/dist/adapters/claude-code/logs.d.ts +54 -0
- package/dist/adapters/claude-code/logs.js +359 -0
- package/dist/adapters/codex/inventory.d.ts +17 -0
- package/dist/adapters/codex/inventory.js +130 -0
- package/dist/adapters/codex/logs.d.ts +22 -0
- package/dist/adapters/codex/logs.js +151 -0
- package/dist/adapters/codex/toml.d.ts +10 -0
- package/dist/adapters/codex/toml.js +76 -0
- package/dist/archive/apply.d.ts +62 -0
- package/dist/archive/apply.js +284 -0
- package/dist/archive/fsops.d.ts +24 -0
- package/dist/archive/fsops.js +95 -0
- package/dist/archive/journal.d.ts +41 -0
- package/dist/archive/journal.js +95 -0
- package/dist/archive/lock.d.ts +2 -0
- package/dist/archive/lock.js +32 -0
- package/dist/archive/manifest.d.ts +37 -0
- package/dist/archive/manifest.js +9 -0
- package/dist/archive/methods.d.ts +46 -0
- package/dist/archive/methods.js +239 -0
- package/dist/archive/paths.d.ts +18 -0
- package/dist/archive/paths.js +61 -0
- package/dist/archive/restore.d.ts +30 -0
- package/dist/archive/restore.js +84 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +329 -0
- package/dist/core/buckets.d.ts +3 -0
- package/dist/core/buckets.js +6 -0
- package/dist/core/frontmatter.d.ts +6 -0
- package/dist/core/frontmatter.js +31 -0
- package/dist/core/hash.d.ts +19 -0
- package/dist/core/hash.js +42 -0
- package/dist/core/messages.d.ts +16 -0
- package/dist/core/messages.js +17 -0
- package/dist/core/scan.d.ts +16 -0
- package/dist/core/scan.js +345 -0
- package/dist/core/summary.d.ts +4 -0
- package/dist/core/summary.js +63 -0
- package/dist/core/types.d.ts +185 -0
- package/dist/core/types.js +3 -0
- package/dist/report/client.d.ts +1 -0
- package/dist/report/client.js +676 -0
- package/dist/report/fix.d.ts +46 -0
- package/dist/report/fix.js +116 -0
- package/dist/report/logo.d.ts +7 -0
- package/dist/report/logo.js +23 -0
- package/dist/report/model.d.ts +103 -0
- package/dist/report/model.js +194 -0
- package/dist/report/render.d.ts +9 -0
- package/dist/report/render.js +45 -0
- package/dist/report/styles.d.ts +1 -0
- package/dist/report/styles.js +202 -0
- package/dist/report/suggest.d.ts +39 -0
- package/dist/report/suggest.js +88 -0
- package/package.json +56 -4
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
// Report styles: tokens and type from design DR10, layout from DR2/DR4/DR11. Native fonts only (the CSP blocks downloads).
|
|
2
|
+
export const STYLES = String.raw `
|
|
3
|
+
:root {
|
|
4
|
+
--bg: #ffffff; --bg-2: #f6f7f8; --ink: #111318; --ink-2: #535b67; --ink-3: #9aa1ab; --line: #e6e8eb; --accent: #111318; --on-accent: #ffffff;
|
|
5
|
+
--seg-1: #27272a; --seg-2: #8a8f98; --seg-3: #c2833a; --seg-4: #cfd2d7; --seg-5: #5b6b8c;
|
|
6
|
+
--green: #15803d; --green-soft: #e9f7ee; --amber: #b45309; --amber-soft: #fff4e0; --red: #b91c1c; --red-soft: #fdecec;
|
|
7
|
+
--font: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI Variable Text", "Segoe UI", system-ui, sans-serif;
|
|
8
|
+
--mono: ui-monospace, "SF Mono", "Cascadia Mono", Menlo, Consolas, monospace;
|
|
9
|
+
color-scheme: light dark;
|
|
10
|
+
}
|
|
11
|
+
@media (prefers-color-scheme: dark) {
|
|
12
|
+
:root {
|
|
13
|
+
--bg: #121317; --bg-2: #1a1c21; --ink: #eef0f3; --ink-2: #aab1bc; --ink-3: #6b7280; --line: #262a31; --accent: #eef0f3; --on-accent: #121317;
|
|
14
|
+
--seg-1: #e4e4e7; --seg-2: #8b919c; --seg-3: #d9993f; --seg-4: #4a4f58; --seg-5: #8fa3c9;
|
|
15
|
+
--green: #34d070; --green-soft: #13261b; --amber: #f5b14b; --amber-soft: #2e2414; --red: #f87171; --red-soft: #2f1a1a;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
@media (prefers-contrast: more) { :root { --ink-2: var(--ink); --line: var(--ink-3); } }
|
|
19
|
+
* { box-sizing: border-box; }
|
|
20
|
+
html { -webkit-text-size-adjust: 100%; }
|
|
21
|
+
body { margin: 0; background: var(--bg); color: var(--ink); font: 14px/1.45 var(--font); font-optical-sizing: auto; -webkit-font-smoothing: antialiased; accent-color: var(--accent); caret-color: var(--accent); scrollbar-color: var(--ink-3) transparent; }
|
|
22
|
+
::selection { background: var(--red-soft); color: var(--ink); }
|
|
23
|
+
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px; }
|
|
24
|
+
button { font: inherit; color: inherit; background: none; border: 0; padding: 0; cursor: pointer; }
|
|
25
|
+
button:disabled { cursor: default; opacity: .5; }
|
|
26
|
+
code, .mono { font-family: var(--mono); font-size: 12.5px; }
|
|
27
|
+
h1, h2, h3, p { margin: 0; }
|
|
28
|
+
/* No orphans: headings balance their lines, prose never ends on a single word. */
|
|
29
|
+
h1, h2, h3 { text-wrap: balance; } p, li, dd { text-wrap: pretty; }
|
|
30
|
+
.num { font-variant-numeric: tabular-nums; }
|
|
31
|
+
.muted { color: var(--ink-2); }
|
|
32
|
+
.sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
|
|
33
|
+
a { color: inherit; text-underline-offset: .15em; } a:visited { color: var(--ink-2); }
|
|
34
|
+
|
|
35
|
+
.wrap { max-width: 1200px; margin: 0 auto; padding: 0 24px; }
|
|
36
|
+
header.mast { border-bottom: 1px solid var(--line); }
|
|
37
|
+
.mast .wrap { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 16px; padding-top: 14px; padding-bottom: 14px; }
|
|
38
|
+
.brand { display: inline-flex; align-items: center; gap: 8px; font-weight: 650; font-size: 17px; letter-spacing: -0.02em; }
|
|
39
|
+
.brand svg { width: 28px; height: 28px; }
|
|
40
|
+
.mast .meta { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 14px; color: var(--ink-2); font-size: 14px; }
|
|
41
|
+
.mast select { font: inherit; color: var(--ink); background: var(--bg); border: 1px solid var(--line); border-radius: 6px; padding: 4px 8px; max-width: 60vw; }
|
|
42
|
+
nav.tabs { border-bottom: 1px solid var(--line); }
|
|
43
|
+
nav.tabs .wrap { display: flex; gap: 4px; overflow-x: auto; scrollbar-width: none; }
|
|
44
|
+
nav.tabs .wrap::-webkit-scrollbar { display: none; }
|
|
45
|
+
[role="tab"] { padding: 12px 12px 10px; border-bottom: 2px solid transparent; color: var(--ink-2); white-space: nowrap; font-weight: 500; }
|
|
46
|
+
[role="tab"][aria-selected="true"] { color: var(--ink); border-bottom-color: var(--ink); }
|
|
47
|
+
main .wrap { padding-top: 28px; padding-bottom: 48px; }
|
|
48
|
+
footer.foot { border-top: 1px solid var(--line); color: var(--ink-2); font-size: 13px; }
|
|
49
|
+
footer.foot .wrap { display: flex; flex-wrap: wrap; gap: 4px 18px; padding-top: 16px; padding-bottom: 120px; }
|
|
50
|
+
footer.foot a:visited { color: var(--ink-2); }
|
|
51
|
+
.panel-title { font-size: 22px; font-weight: 600; letter-spacing: -0.01em; margin: 8px 0 6px; }
|
|
52
|
+
.lede { color: var(--ink-2); font-size: 16px; max-width: 70ch; margin-bottom: 20px; }
|
|
53
|
+
|
|
54
|
+
.banner { border: 1px solid var(--line); background: var(--bg-2); border-radius: 8px; padding: 12px 14px; margin-bottom: 16px; font-size: 16px; display: flex; flex-wrap: wrap; gap: 8px 12px; align-items: center; }
|
|
55
|
+
.banner.warn { border-color: var(--amber); }
|
|
56
|
+
.context { color: var(--ink-2); font-size: 14px; display: flex; flex-wrap: wrap; gap: 4px 12px; }
|
|
57
|
+
.linkish { text-decoration: underline; text-underline-offset: .15em; color: var(--ink-2); }
|
|
58
|
+
|
|
59
|
+
.hero { padding: 8px 0 28px; border-bottom: 1px solid var(--line); }
|
|
60
|
+
.hero h1 { font-size: 30px; line-height: 1.15; font-weight: 650; letter-spacing: -0.02em; margin: 10px 0 14px; max-width: 30ch; }
|
|
61
|
+
.budget { position: relative; height: 22px; border-radius: 6px; background: var(--bg-2); overflow: hidden; display: flex; border: 1px solid var(--line); }
|
|
62
|
+
.budget .listed { background: var(--ink); }
|
|
63
|
+
.budget .dropped { background: repeating-linear-gradient(135deg, var(--red) 0 4px, var(--red-soft) 4px 8px); }
|
|
64
|
+
.budget .edge { position: absolute; top: -4px; bottom: -4px; width: 2px; background: var(--ink); }
|
|
65
|
+
.budget-legend { display: flex; justify-content: space-between; gap: 8px; color: var(--ink-2); font-size: 13px; margin-top: 6px; }
|
|
66
|
+
.hero-line { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 16px; margin-top: 14px; font-size: 16px; }
|
|
67
|
+
.hero-line b { font-weight: 600; }
|
|
68
|
+
.btn { display: inline-flex; align-items: center; gap: 6px; min-height: 36px; padding: 0 14px; border-radius: 6px; border: 1px solid var(--line); background: var(--bg); font-weight: 500; white-space: nowrap; }
|
|
69
|
+
.btn:hover:not(:disabled) { background: var(--bg-2); }
|
|
70
|
+
.btn.primary { background: var(--accent); color: var(--on-accent); border-color: var(--accent); }
|
|
71
|
+
.btn.primary:hover:not(:disabled) { background: var(--accent); opacity: .86; }
|
|
72
|
+
.btn.small { min-height: 30px; padding: 0 10px; font-size: 13px; }
|
|
73
|
+
.strip { display: flex; flex-wrap: wrap; gap: 4px 18px; padding: 14px 0; border-bottom: 1px solid var(--line); color: var(--ink-2); }
|
|
74
|
+
.strip b { color: var(--ink); font-weight: 600; }
|
|
75
|
+
|
|
76
|
+
.hero h1 + .loadbar { margin-top: 4px; }
|
|
77
|
+
.loadbar { display: flex; height: 14px; border-radius: 4px; overflow: hidden; background: var(--bg-2); gap: 2px; }
|
|
78
|
+
.loadbar .seg { display: block; min-width: 3px; }
|
|
79
|
+
.loadbar { position: relative; }
|
|
80
|
+
.loadbar .save { position: absolute; right: 0; top: 0; bottom: 0; background: repeating-linear-gradient(135deg, var(--bg) 0 3px, transparent 3px 6px); box-shadow: inset 2px 0 0 var(--green); }
|
|
81
|
+
.legend .sw.save { background: repeating-linear-gradient(135deg, var(--green) 0 2px, transparent 2px 4px); border: 1px solid var(--green); }
|
|
82
|
+
.legend-item.static { cursor: default; }
|
|
83
|
+
.legend-item.static:hover { background: none; color: var(--ink-2); }
|
|
84
|
+
.seg-agents { background: var(--seg-5); } .seg-agentsmd { background: var(--seg-5); } .seg-plugins { background: var(--seg-3); } .seg-base { background: var(--seg-4); }
|
|
85
|
+
.measured { color: var(--ink-2); font-size: 13px; margin-top: 4px; }
|
|
86
|
+
.seg-mcp { background: var(--seg-1); } .seg-skills { background: var(--seg-2); } .seg-hooks { background: var(--seg-3); } .seg-instr { background: var(--seg-4); }
|
|
87
|
+
.legend { display: flex; flex-wrap: wrap; gap: 2px 6px; margin: 8px 0 0 -8px; }
|
|
88
|
+
.legend-item { display: inline-flex; align-items: center; gap: 6px; padding: 4px 8px; border-radius: 6px; color: var(--ink-2); }
|
|
89
|
+
.legend-item:hover { background: var(--bg-2); color: var(--ink); }
|
|
90
|
+
.legend-item b { color: var(--ink); font-weight: 600; }
|
|
91
|
+
.legend .sw { width: 10px; height: 10px; border-radius: 2px; }
|
|
92
|
+
.fix { border: 1px solid var(--line); border-radius: 8px; margin-top: 20px; background: var(--bg-2); }
|
|
93
|
+
.fix-row { display: flex; flex-wrap: wrap; gap: 10px 20px; align-items: center; justify-content: space-between; padding: 10px 10px 10px 16px; }
|
|
94
|
+
.fix-row p { flex: 1 1 280px; }
|
|
95
|
+
.fix-row b { font-weight: 600; }
|
|
96
|
+
.fix-run { padding: 4px 16px 16px; border-top: 1px solid var(--line); display: grid; gap: 8px; justify-items: start; }
|
|
97
|
+
.fix-run > p:first-child { margin-top: 12px; }
|
|
98
|
+
.fix-run .codebox { width: 100%; background: var(--bg); }
|
|
99
|
+
.byhand { display: grid; gap: 6px; margin-top: 6px; color: var(--ink-2); }
|
|
100
|
+
.byhand p { overflow-wrap: anywhere; }
|
|
101
|
+
.byhand b { color: var(--ink); font-weight: 600; }
|
|
102
|
+
.browse { display: grid; grid-template-columns: 200px minmax(0, 1fr); gap: 0 36px; align-items: start; padding-top: 24px; }
|
|
103
|
+
nav.kinds { position: sticky; top: 16px; display: grid; gap: 2px; }
|
|
104
|
+
.kind { display: grid; grid-template-columns: 1fr auto; align-items: baseline; gap: 0 8px; text-align: left; padding: 8px 10px; border-radius: 6px; color: var(--ink-2); border-left: 2px solid transparent; }
|
|
105
|
+
.kind:hover { background: var(--bg-2); color: var(--ink); }
|
|
106
|
+
.kind[aria-pressed="true"] { background: var(--bg-2); color: var(--ink); font-weight: 600; border-left-color: var(--ink); border-radius: 0 6px 6px 0; }
|
|
107
|
+
.kind .kn { font-size: 13px; color: var(--ink-2); font-weight: 500; }
|
|
108
|
+
.kind .ks { grid-column: 1 / -1; font-size: 12px; color: var(--red); font-weight: 500; }
|
|
109
|
+
.kindhead { padding-bottom: 4px; }
|
|
110
|
+
.kindhead h2 { font-size: 24px; font-weight: 650; letter-spacing: -0.02em; display: flex; align-items: baseline; gap: 10px; }
|
|
111
|
+
.kindhead .kc { font-size: 15px; font-weight: 500; color: var(--ink-2); }
|
|
112
|
+
.kinddesc { color: var(--ink-2); max-width: 70ch; margin-top: 4px; }
|
|
113
|
+
.kindstats { display: flex; flex-wrap: wrap; gap: 4px 18px; margin-top: 10px; color: var(--ink-2); }
|
|
114
|
+
.kindstats b { color: var(--ink); font-weight: 600; }
|
|
115
|
+
.filters { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; padding: 16px 0 12px; }
|
|
116
|
+
.chips { display: flex; flex-wrap: wrap; gap: 6px; }
|
|
117
|
+
.chip { border: 1px solid var(--line); border-radius: 6px; padding: 5px 10px; font-size: 13px; color: var(--ink-2); }
|
|
118
|
+
.chip[aria-pressed="true"] { background: var(--ink); color: var(--bg); border-color: var(--ink); }
|
|
119
|
+
.search { flex: 1 1 220px; max-width: 360px; height: 36px; border: 1px solid var(--line); border-radius: 6px; padding: 0 10px; font: inherit; color: var(--ink); background: var(--bg); }
|
|
120
|
+
.sortsel { height: 36px; border: 1px solid var(--line); border-radius: 6px; padding: 0 8px; font: inherit; color: var(--ink); background: var(--bg); }
|
|
121
|
+
.countline { width: 100%; display: flex; gap: 12px; align-items: center; color: var(--ink-2); font-size: 13px; }
|
|
122
|
+
.filters-toggle { display: none; }
|
|
123
|
+
|
|
124
|
+
table.items { width: 100%; border-collapse: collapse; }
|
|
125
|
+
.items th { text-align: left; font-size: 13px; font-weight: 500; color: var(--ink-2); padding: 8px 10px; border-bottom: 1px solid var(--line); white-space: nowrap; }
|
|
126
|
+
.items th.r, .items td.r { text-align: right; white-space: nowrap; }
|
|
127
|
+
.items td { padding: 10px; border-bottom: 1px solid var(--line); vertical-align: middle; }
|
|
128
|
+
.items td.name { width: 100%; min-width: 180px; }
|
|
129
|
+
.items .nm { font-weight: 500; overflow-wrap: break-word; }
|
|
130
|
+
.items .sub { color: var(--ink-2); font-size: 13px; overflow-wrap: anywhere; }
|
|
131
|
+
.items .unit { display: block; color: var(--ink-2); font-size: 12px; }
|
|
132
|
+
.items tr.marked-archive td { background: var(--red-soft); }
|
|
133
|
+
.items tr.detail td { background: var(--bg-2); padding: 14px 16px 16px 48px; font-size: 14px; }
|
|
134
|
+
.detail dl { display: grid; grid-template-columns: max-content 1fr; gap: 6px 16px; margin: 0; max-width: 100ch; }
|
|
135
|
+
.detail dt { color: var(--ink-2); }
|
|
136
|
+
.detail dd { margin: 0; overflow-wrap: anywhere; }
|
|
137
|
+
.disclose { width: 28px; height: 28px; border-radius: 6px; display: inline-grid; place-items: center; color: var(--ink-2); }
|
|
138
|
+
.disclose svg { width: 12px; height: 12px; transition: transform 120ms ease-out; }
|
|
139
|
+
[aria-expanded="true"] > svg { transform: rotate(90deg); }
|
|
140
|
+
.seg { display: inline-flex; border: 1px solid var(--line); border-radius: 6px; overflow: hidden; }
|
|
141
|
+
.seg button { padding: 4px 8px; font-size: 12.5px; font-weight: 500; color: var(--ink-2); min-height: 28px; }
|
|
142
|
+
.seg button + button { border-left: 1px solid var(--line); }
|
|
143
|
+
.seg button[aria-pressed="true"].a { background: var(--red); color: #fff; }
|
|
144
|
+
.seg button[aria-pressed="true"].k { background: var(--green); color: #fff; }
|
|
145
|
+
.tag { display: inline-block; border-radius: 4px; padding: 0 6px; font-size: 12px; font-weight: 500; background: var(--bg-2); color: var(--ink-2); margin-left: 6px; white-space: nowrap; }
|
|
146
|
+
.tag.red { background: var(--red-soft); color: var(--red); } .tag.green { background: var(--green-soft); color: var(--green); } .tag.amber { background: var(--amber-soft); color: var(--amber); }
|
|
147
|
+
.narrow-meta { display: none; overflow-wrap: anywhere; }
|
|
148
|
+
.impact { background: var(--bg-2); border: 1px solid var(--line); border-radius: 6px; padding: 10px 12px; margin-top: 8px; display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
|
|
149
|
+
|
|
150
|
+
.group { border-top: 1px solid var(--line); padding: 14px 0; }
|
|
151
|
+
.group h2 { font-size: 16px; font-weight: 600; margin-bottom: 6px; }
|
|
152
|
+
.group ul { margin: 0; padding-left: 18px; display: grid; gap: 4px; }
|
|
153
|
+
.codebox { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; background: var(--bg-2); border: 1px solid var(--line); border-radius: 8px; padding: 10px 12px; margin: 6px 0; }
|
|
154
|
+
.codebox code { flex: 1 1 240px; overflow-wrap: anywhere; }
|
|
155
|
+
.next { border: 1px solid var(--ink); border-radius: 8px; padding: 14px 16px; margin: 16px 0; font-size: 16px; }
|
|
156
|
+
.next ol { margin: 8px 0 0; padding-left: 20px; display: grid; gap: 6px; }
|
|
157
|
+
textarea.picksjson { width: 100%; min-height: 120px; font: 12.5px var(--mono); }
|
|
158
|
+
.finding { border-top: 1px solid var(--line); padding: 14px 0; display: grid; grid-template-columns: 12px 1fr; gap: 4px 12px; }
|
|
159
|
+
.finding i { width: 8px; height: 8px; border-radius: 50%; margin-top: 7px; background: var(--amber); }
|
|
160
|
+
.finding.high i { background: var(--red); } .finding.good i { background: var(--green); }
|
|
161
|
+
.finding h2 { font-size: 16px; font-weight: 600; } .finding p { grid-column: 2; color: var(--ink-2); max-width: 80ch; }
|
|
162
|
+
|
|
163
|
+
.picksbar { position: fixed; left: 0; right: 0; bottom: 0; background: var(--bg); border-top: 1px solid var(--line); box-shadow: 0 2px 8px rgba(0,0,0,.12); padding: 10px 24px calc(10px + env(safe-area-inset-bottom, 0px)); display: flex; align-items: center; gap: 12px; z-index: 5; }
|
|
164
|
+
.picksbar[hidden] { display: none; }
|
|
165
|
+
.picksbar .count { font-weight: 600; }
|
|
166
|
+
@media (prefers-reduced-motion: reduce) { .disclose svg { transition: none; } }
|
|
167
|
+
|
|
168
|
+
/* A narrower sidebar just above the breakpoint, so wide system fonts (Linux, Windows) still fit the table. */
|
|
169
|
+
@media (max-width: 1279px) { .browse { grid-template-columns: 168px minmax(0, 1fr); gap: 0 24px; } .items td.name { min-width: 150px; } }
|
|
170
|
+
/* With the sidebar open, the source column goes first: the source already sits under each name. */
|
|
171
|
+
@media (max-width: 1399px) { .col-source { display: none; } }
|
|
172
|
+
@media (max-width: 1099px) { .col-source, .col-last { display: none; } .items td.name { min-width: 140px; } .items td, .items th { padding-left: 7px; padding-right: 7px; } }
|
|
173
|
+
@media (max-width: 1099px) {
|
|
174
|
+
.browse { display: block; padding-top: 16px; }
|
|
175
|
+
nav.kinds { position: static; display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 18px; }
|
|
176
|
+
.kind { display: inline-flex; gap: 6px; padding: 5px 10px; border: 1px solid var(--line); border-radius: 6px; font-size: 13px; }
|
|
177
|
+
.kind[aria-pressed="true"] { background: var(--ink); color: var(--bg); border-color: var(--ink); border-radius: 6px; font-weight: 500; }
|
|
178
|
+
.kind[aria-pressed="true"] .kn { color: inherit; }
|
|
179
|
+
.kind .ks { display: none; }
|
|
180
|
+
.kindhead h2 { font-size: 20px; }
|
|
181
|
+
}
|
|
182
|
+
@media (max-width: 719px) {
|
|
183
|
+
.wrap { padding: 0 16px; }
|
|
184
|
+
.hero h1 { font-size: 24px; }
|
|
185
|
+
.filters .more { display: none; width: 100%; }
|
|
186
|
+
body.filters-open .filters .more { display: flex; flex-wrap: wrap; gap: 8px; }
|
|
187
|
+
.filters-toggle { display: inline-flex; }
|
|
188
|
+
.items thead { display: none; }
|
|
189
|
+
.items .col-2nd { display: none; }
|
|
190
|
+
.items td.name { min-width: 0; }
|
|
191
|
+
.items .nm { overflow-wrap: anywhere; }
|
|
192
|
+
.items .tag { white-space: normal; margin-left: 0; }
|
|
193
|
+
.items td { word-break: normal; }
|
|
194
|
+
.narrow-meta { display: block; color: var(--ink-2); font-size: 13px; }
|
|
195
|
+
.items td { padding: 10px 6px; }
|
|
196
|
+
.items tr.detail td { padding-left: 12px; }
|
|
197
|
+
.btn, .chip, .kind, .legend-item, .seg button, .disclose, [role="tab"], .search, .sortsel { min-height: 44px; }
|
|
198
|
+
.disclose { width: 44px; }
|
|
199
|
+
footer.foot .wrap { padding-bottom: 140px; }
|
|
200
|
+
.picksbar { padding-left: 16px; padding-right: 16px; }
|
|
201
|
+
}
|
|
202
|
+
`;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { Inventory } from '../core/types.js';
|
|
2
|
+
/** Thresholds printed beside the suggestion button (design DR6). */
|
|
3
|
+
export declare const MIN_SESSIONS = 20;
|
|
4
|
+
export declare const MIN_DAYS = 14;
|
|
5
|
+
export type NotSuggested = 'used' | 'too-new' | 'too-few-sessions' | 'ambiguous' | 'uncertain' | 'parse-gaps' | 'manual' | 'kept' | 'off' | 'plugin-in-use' | 'not-removable';
|
|
6
|
+
export interface Suggestion {
|
|
7
|
+
suggested: boolean;
|
|
8
|
+
reason?: NotSuggested;
|
|
9
|
+
/** Sessions and days the item could have been used in (design-delta DE5). */
|
|
10
|
+
windowSessions: number;
|
|
11
|
+
windowDays: number;
|
|
12
|
+
/** Unreadable log lines inside the item's window (DE6). */
|
|
13
|
+
unreadableLines: number;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Decides, per item, whether the report may suggest archiving it. Usage for global items is counted across
|
|
17
|
+
* all projects (DE1); the window starts when the item was first seen (DE5); unreadable lines inside the window
|
|
18
|
+
* block a suggestion (DE6); a plugin child is suggested only when its whole plugin could go (DE7).
|
|
19
|
+
*/
|
|
20
|
+
export declare function suggestions(inv: Inventory, keptIds: Set<string>): Map<string, Suggestion>;
|
|
21
|
+
/** One line of the skill listing, for projecting it after some skills go. */
|
|
22
|
+
export interface ListingEntry {
|
|
23
|
+
name: string;
|
|
24
|
+
fullChars: number;
|
|
25
|
+
nameChars: number;
|
|
26
|
+
priority: boolean;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Projects the skill listing Claude Code builds: every name first, then the descriptions of skills it counts as
|
|
30
|
+
* used (and its own bundled skills), then the rest in listing order, each one that still fits under the size cap.
|
|
31
|
+
* This matches the listings packlight has observed (2.1.29x); it is a projection and always labelled as one.
|
|
32
|
+
* Self-contained: the report serialises it with Function.toString.
|
|
33
|
+
*/
|
|
34
|
+
export declare function simulateListing(entries: ListingEntry[], budgetChars: number): {
|
|
35
|
+
chars: number;
|
|
36
|
+
described: number;
|
|
37
|
+
dropped: number;
|
|
38
|
+
describedNames: string[];
|
|
39
|
+
};
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/** Thresholds printed beside the suggestion button (design DR6). */
|
|
2
|
+
export const MIN_SESSIONS = 20;
|
|
3
|
+
export const MIN_DAYS = 14;
|
|
4
|
+
const DAY = 86_400_000;
|
|
5
|
+
/**
|
|
6
|
+
* Decides, per item, whether the report may suggest archiving it. Usage for global items is counted across
|
|
7
|
+
* all projects (DE1); the window starts when the item was first seen (DE5); unreadable lines inside the window
|
|
8
|
+
* block a suggestion (DE6); a plugin child is suggested only when its whole plugin could go (DE7).
|
|
9
|
+
*/
|
|
10
|
+
export function suggestions(inv, keptIds) {
|
|
11
|
+
const scanTime = Date.parse(inv.window.to);
|
|
12
|
+
const windowFrom = inv.window.from ? Date.parse(inv.window.from) : scanTime;
|
|
13
|
+
const sessions = inv.sessions.filter(s => s.start);
|
|
14
|
+
const own = (it) => {
|
|
15
|
+
const from = Math.max(windowFrom, it.firstSeen ? Date.parse(it.firstSeen) : windowFrom);
|
|
16
|
+
const inWindow = sessions.filter(s => Date.parse(s.start) >= from && (it.projectRoot === null || s.projectRoot === it.projectRoot));
|
|
17
|
+
const base = {
|
|
18
|
+
suggested: false,
|
|
19
|
+
windowSessions: inWindow.length,
|
|
20
|
+
windowDays: Math.floor((scanTime - from) / DAY),
|
|
21
|
+
unreadableLines: inWindow.reduce((n, s) => n + s.unreadableLines, 0),
|
|
22
|
+
};
|
|
23
|
+
const no = (reason) => ({ ...base, reason });
|
|
24
|
+
if (it.kind === 'instructions')
|
|
25
|
+
return no('not-removable');
|
|
26
|
+
if (it.removal.method === 'manual')
|
|
27
|
+
return no('manual');
|
|
28
|
+
if (it.name === 'packlight' || it.name.endsWith(':packlight'))
|
|
29
|
+
return no('not-removable');
|
|
30
|
+
if (!it.enabled)
|
|
31
|
+
return no('off');
|
|
32
|
+
if (keptIds.has(it.id))
|
|
33
|
+
return no('kept');
|
|
34
|
+
if (it.usage.ambiguous)
|
|
35
|
+
return no('ambiguous');
|
|
36
|
+
if (it.usage.uncertain)
|
|
37
|
+
return no('uncertain');
|
|
38
|
+
if (it.usage.total > 0)
|
|
39
|
+
return no('used');
|
|
40
|
+
if (base.windowDays < MIN_DAYS)
|
|
41
|
+
return no('too-new');
|
|
42
|
+
if (base.windowSessions < MIN_SESSIONS)
|
|
43
|
+
return no('too-few-sessions');
|
|
44
|
+
if (base.unreadableLines > 0)
|
|
45
|
+
return no('parse-gaps');
|
|
46
|
+
return { ...base, suggested: true };
|
|
47
|
+
};
|
|
48
|
+
const result = new Map();
|
|
49
|
+
for (const it of inv.items)
|
|
50
|
+
result.set(it.id, own(it));
|
|
51
|
+
// Plugins are judged as a whole (DE7): every part must be eligible on its own, and nothing in it kept.
|
|
52
|
+
for (const plugin of inv.items.filter(i => i.kind === 'plugin')) {
|
|
53
|
+
const parts = inv.items.filter(i => i.plugin === plugin.plugin && i.kind !== 'plugin');
|
|
54
|
+
const self = result.get(plugin.id);
|
|
55
|
+
const partBlocked = parts.find(p => !result.get(p.id).suggested);
|
|
56
|
+
const whole = !self.suggested ? self
|
|
57
|
+
: partBlocked ? { ...self, suggested: false, reason: result.get(partBlocked.id).reason === 'used' ? 'plugin-in-use' : result.get(partBlocked.id).reason }
|
|
58
|
+
: self;
|
|
59
|
+
result.set(plugin.id, whole);
|
|
60
|
+
for (const p of parts) {
|
|
61
|
+
const mine = result.get(p.id);
|
|
62
|
+
result.set(p.id, whole.suggested ? mine : { ...mine, suggested: false, reason: mine.suggested ? (whole.reason === 'used' ? 'plugin-in-use' : whole.reason) : mine.reason });
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return result;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Projects the skill listing Claude Code builds: every name first, then the descriptions of skills it counts as
|
|
69
|
+
* used (and its own bundled skills), then the rest in listing order, each one that still fits under the size cap.
|
|
70
|
+
* This matches the listings packlight has observed (2.1.29x); it is a projection and always labelled as one.
|
|
71
|
+
* Self-contained: the report serialises it with Function.toString.
|
|
72
|
+
*/
|
|
73
|
+
export function simulateListing(entries, budgetChars) {
|
|
74
|
+
let used = entries.reduce((n, e) => n + e.nameChars, 0);
|
|
75
|
+
const describedNames = [];
|
|
76
|
+
for (const pass of [true, false]) {
|
|
77
|
+
for (const e of entries) {
|
|
78
|
+
if (e.priority !== pass)
|
|
79
|
+
continue;
|
|
80
|
+
const extra = e.fullChars - e.nameChars;
|
|
81
|
+
if (extra > 0 && used + extra <= budgetChars) {
|
|
82
|
+
used += extra;
|
|
83
|
+
describedNames.push(e.name);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return { chars: used, described: describedNames.length, dropped: entries.length - describedNames.length, describedNames };
|
|
88
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,58 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "packlight-cli",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "See what your coding agent carries, keep what you use, archive the rest.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"claude-code",
|
|
7
|
+
"claude",
|
|
8
|
+
"mcp",
|
|
9
|
+
"skills",
|
|
10
|
+
"hooks",
|
|
11
|
+
"context",
|
|
12
|
+
"tokens",
|
|
13
|
+
"cli",
|
|
14
|
+
"developer-tools"
|
|
15
|
+
],
|
|
16
|
+
"license": "MIT",
|
|
17
|
+
"author": "Cooper Kao (https://github.com/cooperism-lab)",
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "git+https://github.com/cooperism-lab/packlight.git"
|
|
21
|
+
},
|
|
22
|
+
"homepage": "https://github.com/cooperism-lab/packlight#readme",
|
|
23
|
+
"bugs": {
|
|
24
|
+
"url": "https://github.com/cooperism-lab/packlight/issues"
|
|
25
|
+
},
|
|
26
|
+
"type": "module",
|
|
27
|
+
"bin": {
|
|
28
|
+
"packlight": "dist/cli.js"
|
|
29
|
+
},
|
|
30
|
+
"files": [
|
|
31
|
+
"dist",
|
|
32
|
+
"CHANGELOG.md"
|
|
33
|
+
],
|
|
34
|
+
"engines": {
|
|
35
|
+
"node": ">=20"
|
|
36
|
+
},
|
|
37
|
+
"scripts": {
|
|
38
|
+
"build": "tsc -p tsconfig.build.json",
|
|
39
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
40
|
+
"test": "vitest run",
|
|
41
|
+
"scan": "node --import tsx src/cli.ts scan",
|
|
42
|
+
"e2e": "npm run build && playwright test",
|
|
43
|
+
"prepublishOnly": "npm run typecheck && npm test && npm run build",
|
|
44
|
+
"demo": "npm run build && node --import tsx scripts/build-demo.mts"
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@axe-core/playwright": "4.13.0",
|
|
48
|
+
"@playwright/test": "1.64.0",
|
|
49
|
+
"@types/node": "22.20.5",
|
|
50
|
+
"@types/write-file-atomic": "4.0.3",
|
|
51
|
+
"tsx": "4.23.15",
|
|
52
|
+
"typescript": "5.9.3",
|
|
53
|
+
"vitest": "3.2.7"
|
|
54
|
+
},
|
|
55
|
+
"dependencies": {
|
|
56
|
+
"write-file-atomic": "6.0.0"
|
|
57
|
+
}
|
|
58
|
+
}
|