@pugi/cli 0.1.0-beta.5 → 0.1.0-beta.51
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/THIRD_PARTY_NOTICES.md +40 -0
- package/assets/pugi-mascot.ansi +15 -25
- package/assets/pugi-prozr2-mascot.ansi +9 -0
- package/bin/run.js +33 -1
- package/dist/commands/jobs-watch.js +201 -0
- package/dist/commands/jobs.js +15 -0
- package/dist/commands/smoke.js +133 -0
- package/dist/core/agent-progress/cleanup.js +134 -0
- package/dist/core/agent-progress/schema.js +144 -0
- package/dist/core/agent-progress/writer.js +101 -0
- package/dist/core/artifact-chain/dispatcher.js +148 -0
- package/dist/core/artifact-chain/exporter.js +164 -0
- package/dist/core/artifact-chain/state.js +243 -0
- package/dist/core/artifact-chain/steps.js +169 -0
- package/dist/core/auth/ensure-authenticated.js +129 -0
- package/dist/core/auth/env-provider.js +238 -0
- package/dist/core/auto-update/channels.js +122 -0
- package/dist/core/auto-update/checker.js +241 -0
- package/dist/core/auto-update/state.js +235 -0
- package/dist/core/bare-mode/index.js +107 -0
- package/dist/core/bash-classifier.js +400 -4
- package/dist/core/checkpoint/resumer.js +149 -0
- package/dist/core/checkpoint/rewinder.js +291 -0
- package/dist/core/codegraph/decision-store.js +248 -0
- package/dist/core/codegraph/detect-repo.js +459 -0
- package/dist/core/codegraph/install.js +134 -0
- package/dist/core/codegraph/offer-hook.js +220 -0
- package/dist/core/compact/auto-trigger.js +96 -0
- package/dist/core/compact/buffer-rewriter.js +115 -0
- package/dist/core/compact/summarizer.js +208 -0
- package/dist/core/compact/token-counter.js +108 -0
- package/dist/core/consensus/diff-capture.js +112 -3
- package/dist/core/context/index.js +7 -0
- package/dist/core/context/markdown-traverse.js +255 -0
- package/dist/core/cost/rate-card.js +129 -0
- package/dist/core/cost/tracker.js +221 -0
- package/dist/core/denial-tracking/index.js +8 -0
- package/dist/core/denial-tracking/state.js +264 -0
- package/dist/core/diagnostics/probe-runner.js +93 -0
- package/dist/core/diagnostics/probes/api.js +46 -0
- package/dist/core/diagnostics/probes/auth.js +86 -0
- package/dist/core/diagnostics/probes/bare-mode.js +42 -0
- package/dist/core/diagnostics/probes/cli-version.js +127 -0
- package/dist/core/diagnostics/probes/config.js +72 -0
- package/dist/core/diagnostics/probes/denial-tracking.js +57 -0
- package/dist/core/diagnostics/probes/disk.js +81 -0
- package/dist/core/diagnostics/probes/git.js +65 -0
- package/dist/core/diagnostics/probes/hooks.js +118 -0
- package/dist/core/diagnostics/probes/mcp.js +75 -0
- package/dist/core/diagnostics/probes/node.js +59 -0
- package/dist/core/diagnostics/probes/pnpm.js +36 -0
- package/dist/core/diagnostics/probes/pugi-md.js +89 -0
- package/dist/core/diagnostics/probes/sandbox.js +40 -0
- package/dist/core/diagnostics/probes/session.js +74 -0
- package/dist/core/diagnostics/probes/status-snapshot.js +488 -0
- package/dist/core/diagnostics/probes/workspace.js +63 -0
- package/dist/core/diagnostics/types.js +70 -0
- package/dist/core/dispatch/cache-cleanup.js +197 -0
- package/dist/core/dispatch/cache-handoff.js +295 -0
- package/dist/core/edits/dispatch.js +218 -2
- package/dist/core/edits/journal.js +199 -0
- package/dist/core/edits/layer-d-ast.js +557 -14
- package/dist/core/edits/verify-hook.js +273 -0
- package/dist/core/edits/worktree.js +322 -0
- package/dist/core/engine/anvil-client.js +115 -5
- package/dist/core/engine/auto-compact.js +179 -0
- package/dist/core/engine/budgets.js +155 -0
- package/dist/core/engine/context-prefix.js +155 -0
- package/dist/core/engine/intent.js +260 -0
- package/dist/core/engine/native-pugi.js +897 -211
- package/dist/core/engine/prompts.js +88 -2
- package/dist/core/engine/strip-internal-fields.js +124 -0
- package/dist/core/engine/tool-bridge.js +1045 -36
- package/dist/core/feedback/queue.js +177 -0
- package/dist/core/feedback/submitter.js +145 -0
- package/dist/core/file-cache.js +113 -1
- package/dist/core/hooks/events.js +44 -0
- package/dist/core/hooks/index.js +15 -0
- package/dist/core/hooks/registry.js +213 -0
- package/dist/core/hooks/runner.js +236 -0
- package/dist/core/hooks/v2/event-emitter.js +115 -0
- package/dist/core/hooks/v2/executor.js +282 -0
- package/dist/core/hooks/v2/index.js +25 -0
- package/dist/core/hooks/v2/lifecycle.js +104 -0
- package/dist/core/hooks/v2/loader.js +216 -0
- package/dist/core/hooks/v2/matcher.js +125 -0
- package/dist/core/hooks/v2/trust.js +143 -0
- package/dist/core/hooks/v2/types.js +86 -0
- package/dist/core/lsp/cache.js +105 -0
- package/dist/core/lsp/client.js +776 -0
- package/dist/core/lsp/language-detect.js +66 -0
- package/dist/core/lsp/post-edit-diagnostics.js +171 -0
- package/dist/core/mcp/client.js +75 -6
- package/dist/core/mcp/http-server.js +553 -0
- package/dist/core/mcp/orchestrator-tools.js +662 -0
- package/dist/core/mcp/permission.js +190 -0
- package/dist/core/mcp/registry.js +24 -2
- package/dist/core/mcp/server-tools.js +219 -0
- package/dist/core/mcp/server.js +397 -0
- package/dist/core/memory/dual-write.js +416 -0
- package/dist/core/memory/phase1-kinds.js +20 -0
- package/dist/core/memory-sync/queue.js +158 -0
- package/dist/core/onboarding/ensure-initialized.js +133 -0
- package/dist/core/onboarding/marker.js +111 -0
- package/dist/core/onboarding/telemetry-state.js +108 -0
- package/dist/core/output-style/presets.js +176 -0
- package/dist/core/output-style/state.js +185 -0
- package/dist/core/path-security.js +284 -2
- package/dist/core/permissions/auto-classifier.js +124 -0
- package/dist/core/permissions/circuit-breaker.js +83 -0
- package/dist/core/permissions/gate.js +278 -0
- package/dist/core/permissions/index.js +20 -0
- package/dist/core/permissions/mode.js +174 -0
- package/dist/core/permissions/state.js +241 -0
- package/dist/core/permissions/tool-class.js +93 -0
- package/dist/core/prd-check/parser.js +215 -0
- package/dist/core/prd-check/reporter.js +127 -0
- package/dist/core/prd-check/session-review.js +557 -0
- package/dist/core/prd-check/verifiers.js +223 -0
- package/dist/core/pugi-md/context-injector.js +76 -0
- package/dist/core/pugi-md/walk-up.js +207 -0
- package/dist/core/release-notes/parser.js +241 -0
- package/dist/core/release-notes/state.js +116 -0
- package/dist/core/repl/history.js +11 -1
- package/dist/core/repl/model-pricing.js +135 -0
- package/dist/core/repl/session.js +1897 -37
- package/dist/core/repl/slash-commands.js +430 -15
- package/dist/core/repl/store/session-store.js +31 -2
- package/dist/core/repl/workspace-context.js +22 -0
- package/dist/core/repo-map/build.js +125 -0
- package/dist/core/repo-map/cache.js +185 -0
- package/dist/core/repo-map/extractor.js +254 -0
- package/dist/core/repo-map/formatter.js +145 -0
- package/dist/core/repo-map/scanner.js +211 -0
- package/dist/core/retry-budget/budget.js +284 -0
- package/dist/core/retry-budget/index.js +5 -0
- package/dist/core/session.js +92 -0
- package/dist/core/settings.js +80 -0
- package/dist/core/share/formatter.js +271 -0
- package/dist/core/share/redactor.js +221 -0
- package/dist/core/share/uploader.js +267 -0
- package/dist/core/skills/defaults.js +457 -0
- package/dist/core/smoke/headless-driver.js +174 -0
- package/dist/core/smoke/orchestrator.js +194 -0
- package/dist/core/smoke/runner.js +238 -0
- package/dist/core/smoke/scenario-parser.js +316 -0
- package/dist/core/subagents/dispatcher-real.js +600 -0
- package/dist/core/subagents/dispatcher.js +113 -24
- package/dist/core/subagents/index.js +18 -5
- package/dist/core/subagents/isolation-matrix.js +213 -0
- package/dist/core/subagents/spawn.js +19 -4
- package/dist/core/telemetry/emitter.js +229 -0
- package/dist/core/telemetry/queue.js +251 -0
- package/dist/core/theme/context.js +91 -0
- package/dist/core/theme/presets.js +228 -0
- package/dist/core/theme/state.js +181 -0
- package/dist/core/todos/invariant.js +10 -0
- package/dist/core/todos/state.js +177 -0
- package/dist/core/transport/version-interceptor.js +166 -0
- package/dist/core/vim/keymap.js +288 -0
- package/dist/core/vim/state.js +92 -0
- package/dist/core/worktree-manager/cleanup.js +123 -0
- package/dist/core/worktree-manager/manager.js +303 -0
- package/dist/index.js +28 -0
- package/dist/runtime/bootstrap.js +190 -0
- package/dist/runtime/cli.js +3241 -343
- package/dist/runtime/commands/cancel.js +231 -0
- package/dist/runtime/commands/chain.js +489 -0
- package/dist/runtime/commands/codegraph-status.js +227 -0
- package/dist/runtime/commands/compact.js +297 -0
- package/dist/runtime/commands/cost.js +199 -0
- package/dist/runtime/commands/delegate.js +242 -11
- package/dist/runtime/commands/dispatch.js +126 -0
- package/dist/runtime/commands/doctor.js +412 -0
- package/dist/runtime/commands/feedback.js +184 -0
- package/dist/runtime/commands/hooks.js +184 -0
- package/dist/runtime/commands/lsp.js +368 -0
- package/dist/runtime/commands/mcp.js +879 -0
- package/dist/runtime/commands/memory.js +508 -0
- package/dist/runtime/commands/model.js +237 -0
- package/dist/runtime/commands/onboarding.js +275 -0
- package/dist/runtime/commands/patch.js +128 -0
- package/dist/runtime/commands/permissions.js +112 -0
- package/dist/runtime/commands/plan.js +143 -0
- package/dist/runtime/commands/prd-check.js +285 -0
- package/dist/runtime/commands/redo-blob-store.js +92 -0
- package/dist/runtime/commands/redo.js +361 -0
- package/dist/runtime/commands/release-notes.js +229 -0
- package/dist/runtime/commands/repo-map.js +95 -0
- package/dist/runtime/commands/report.js +299 -0
- package/dist/runtime/commands/resume.js +118 -0
- package/dist/runtime/commands/review-consensus.js +17 -2
- package/dist/runtime/commands/rewind.js +333 -0
- package/dist/runtime/commands/sessions.js +163 -0
- package/dist/runtime/commands/share.js +316 -0
- package/dist/runtime/commands/status.js +186 -0
- package/dist/runtime/commands/stickers.js +82 -0
- package/dist/runtime/commands/style.js +194 -0
- package/dist/runtime/commands/theme.js +196 -0
- package/dist/runtime/commands/undo.js +32 -0
- package/dist/runtime/commands/update.js +289 -0
- package/dist/runtime/commands/vim.js +140 -0
- package/dist/runtime/commands/worktree.js +177 -0
- package/dist/runtime/commands/worktrees.js +155 -0
- package/dist/runtime/headless-repl.js +195 -0
- package/dist/runtime/headless.js +543 -0
- package/dist/runtime/load-hooks-or-exit.js +71 -0
- package/dist/runtime/plan-decompose.js +531 -0
- package/dist/runtime/version.js +65 -0
- package/dist/tools/agent-tool.js +229 -0
- package/dist/tools/apply-patch.js +556 -0
- package/dist/tools/ask-user-question.js +213 -0
- package/dist/tools/ask-user.js +115 -0
- package/dist/tools/bash.js +203 -4
- package/dist/tools/file-tools.js +85 -14
- package/dist/tools/lsp-tools.js +189 -0
- package/dist/tools/mcp-tool.js +260 -0
- package/dist/tools/multi-edit.js +361 -0
- package/dist/tools/powershell.js +268 -0
- package/dist/tools/registry.js +51 -0
- package/dist/tools/skill-tool.js +96 -0
- package/dist/tools/tasks.js +208 -0
- package/dist/tools/todo-write.js +184 -0
- package/dist/tools/web-fetch.js +147 -2
- package/dist/tools/web-search.js +458 -0
- package/dist/tui/agent-progress-card.js +111 -0
- package/dist/tui/agent-tree.js +10 -0
- package/dist/tui/ask-modal.js +2 -2
- package/dist/tui/ask-user-question-prompt.js +192 -0
- package/dist/tui/compact-banner.js +81 -0
- package/dist/tui/conversation-pane.js +82 -8
- package/dist/tui/cost-table.js +111 -0
- package/dist/tui/doctor-table.js +46 -0
- package/dist/tui/feedback-prompt.js +156 -0
- package/dist/tui/input-box.js +218 -3
- package/dist/tui/markdown-render.js +4 -4
- package/dist/tui/onboarding-wizard.js +240 -0
- package/dist/tui/permissions-picker.js +86 -0
- package/dist/tui/render.js +35 -0
- package/dist/tui/repl-render.js +313 -35
- package/dist/tui/repl-splash-art.js +1 -1
- package/dist/tui/repl-splash-mascot.js +32 -8
- package/dist/tui/repl-splash.js +2 -2
- package/dist/tui/repl.js +85 -5
- package/dist/tui/splash.js +1 -1
- package/dist/tui/status-bar.js +94 -16
- package/dist/tui/status-table.js +7 -0
- package/dist/tui/stickers-art.js +136 -0
- package/dist/tui/style-table.js +28 -0
- package/dist/tui/theme-table.js +29 -0
- package/dist/tui/thinking-spinner.js +123 -0
- package/dist/tui/tool-stream-pane.js +52 -3
- package/dist/tui/update-banner.js +27 -2
- package/dist/tui/vim-input.js +267 -0
- package/dist/tui/welcome-banner.js +107 -0
- package/dist/tui/welcome-data.js +293 -0
- package/docs/examples/codegraph.mcp.json +10 -0
- package/package.json +13 -7
- package/test/scenarios/codegen-create-file.scenario.txt +13 -0
- package/test/scenarios/compact-force.scenario.txt +11 -0
- package/test/scenarios/identity.scenario.txt +11 -0
- package/test/scenarios/persona-handoff.scenario.txt +11 -0
- package/test/scenarios/walkback.scenario.txt +12 -0
- package/dist/core/engine/compaction-hook.js +0 -154
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure data layer for the `<WelcomeBanner />` component (CEO P0 #2,
|
|
3
|
+
* 2026-05-29). Lives in its own module so it can be unit-tested without
|
|
4
|
+
* rendering Ink, and so the banner component itself contains zero IO.
|
|
5
|
+
*
|
|
6
|
+
* The banner is the CC-style 2-column boxed greeting that replaces the
|
|
7
|
+
* α6.14 wave-3 `<ReplSplash />` on the bare REPL boot path. It mirrors
|
|
8
|
+
* Claude Code's boot layout:
|
|
9
|
+
*
|
|
10
|
+
* ╭────── Pugi v0.1.0-beta.46 ──────╮
|
|
11
|
+
* │ │ Tips for getting started
|
|
12
|
+
* │ Welcome back Yurii! │ Run /init to create PUGI.md...
|
|
13
|
+
* │ │ ───────────
|
|
14
|
+
* │ ▗ ▗ ▖ ▖ │ What's new
|
|
15
|
+
* │ ▘▘ ▝▝ │ * 0.1.0-beta.26 — Wave 6 RAG ...
|
|
16
|
+
* │ Sonnet 4.6 (1M context) · Founder
|
|
17
|
+
* │ yuriy.bulah@gmail.com · pugi-io Org
|
|
18
|
+
* │ /Volumes/T9/Web/.../TestRepos2 │
|
|
19
|
+
* ╰──────────────────────────────────╯
|
|
20
|
+
*
|
|
21
|
+
* Data sources, in priority order:
|
|
22
|
+
*
|
|
23
|
+
* - Account email + tenant + plan: JWT principal decoded from the
|
|
24
|
+
* active credential. Falls back to anonymous label when no
|
|
25
|
+
* credential is on disk (operator boots `pugi` before login).
|
|
26
|
+
* - Greeting first-name: best-effort split of the local part of the
|
|
27
|
+
* email. Falls back к "operator" when unauthenticated.
|
|
28
|
+
* - Model: env override `PUGI_ENGINE_MODEL_CODE`, then the operator's
|
|
29
|
+
* workspace settings `defaultModel`, then "Sonnet 4.6 (1M context)"
|
|
30
|
+
* as the locked α7 default.
|
|
31
|
+
* - Cwd: absolute path of `process.cwd()` — banner left column shows
|
|
32
|
+
* the full path so the operator confirms они are в the right repo.
|
|
33
|
+
* - What's new: top 3 release-note titles from `apps/pugi-cli/CHANGELOG.md`
|
|
34
|
+
* newer than `~/.pugi/.last-seen-version`. Falls back к the top 3
|
|
35
|
+
* overall when last-seen marker is missing. Each entry is a one-line
|
|
36
|
+
* headline ("0.1.0-beta.26 — Wave 6 RAG consumer middleware") trimmed
|
|
37
|
+
* к 60 chars so the right column does not wrap on a 100-col terminal.
|
|
38
|
+
*
|
|
39
|
+
* Every resolver swallows its IO error and returns the documented
|
|
40
|
+
* fallback so a partial environment (missing CHANGELOG, malformed JWT,
|
|
41
|
+
* unreadable settings) never blocks the banner.
|
|
42
|
+
*/
|
|
43
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
44
|
+
import { homedir } from 'node:os';
|
|
45
|
+
import { dirname, resolve as resolvePath } from 'node:path';
|
|
46
|
+
import { fileURLToPath } from 'node:url';
|
|
47
|
+
import { DEFAULT_API_URL, normalizeApiUrl, readCredentialsFile, resolveActiveCredential, } from '../core/credentials.js';
|
|
48
|
+
import { parseChangelog } from '../core/release-notes/parser.js';
|
|
49
|
+
function decodeJwtPayload(token) {
|
|
50
|
+
try {
|
|
51
|
+
const parts = token.split('.');
|
|
52
|
+
if (parts.length < 2)
|
|
53
|
+
return null;
|
|
54
|
+
const payload = parts[1];
|
|
55
|
+
if (!payload)
|
|
56
|
+
return null;
|
|
57
|
+
const padded = payload
|
|
58
|
+
.replace(/-/g, '+')
|
|
59
|
+
.replace(/_/g, '/')
|
|
60
|
+
.padEnd(payload.length + ((4 - (payload.length % 4)) % 4), '=');
|
|
61
|
+
const json = Buffer.from(padded, 'base64').toString('utf8');
|
|
62
|
+
const obj = JSON.parse(json);
|
|
63
|
+
if (!obj || typeof obj !== 'object')
|
|
64
|
+
return null;
|
|
65
|
+
return {
|
|
66
|
+
...(typeof obj.sub === 'string' && { sub: obj.sub }),
|
|
67
|
+
...(typeof obj.email === 'string' && { email: obj.email }),
|
|
68
|
+
...(typeof obj.customerId === 'string' && { customerId: obj.customerId }),
|
|
69
|
+
...(typeof obj.plan === 'string' && { plan: obj.plan }),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/* ------------------------------------------------------------------ */
|
|
77
|
+
/* Resolvers */
|
|
78
|
+
/* ------------------------------------------------------------------ */
|
|
79
|
+
/**
|
|
80
|
+
* Derive a greeting first-name from an email's local part. The split
|
|
81
|
+
* is intentionally aggressive: dot-separated, hyphen-separated, and
|
|
82
|
+
* digit-stripped so `yuriy.bulah@gmail.com` resolves к "Yuriy" instead
|
|
83
|
+
* of "yuriy.bulah". Title-cases the first segment. Falls back к
|
|
84
|
+
* "operator" when no email is available.
|
|
85
|
+
*
|
|
86
|
+
* Export so the spec can lock the heuristic against edge cases (numeric
|
|
87
|
+
* local part, plus-tag aliases, single-letter local part).
|
|
88
|
+
*/
|
|
89
|
+
export function deriveGreetingName(email) {
|
|
90
|
+
if (!email || typeof email !== 'string')
|
|
91
|
+
return 'operator';
|
|
92
|
+
const at = email.indexOf('@');
|
|
93
|
+
if (at <= 0)
|
|
94
|
+
return 'operator';
|
|
95
|
+
const local = email.slice(0, at);
|
|
96
|
+
// Strip plus-tag aliases (`name+tag@host` → `name`).
|
|
97
|
+
const noTag = local.split('+')[0] ?? local;
|
|
98
|
+
// First dot / hyphen / underscore segment wins; this is the
|
|
99
|
+
// colloquial "given name" surface for the vast majority of work
|
|
100
|
+
// emails ("first.last@..." / "first-last@...").
|
|
101
|
+
const firstSegment = noTag.split(/[._-]/)[0] ?? noTag;
|
|
102
|
+
// Strip trailing digits some signup flows append (`yurii2@`) so the
|
|
103
|
+
// greeting reads as a name, not a username.
|
|
104
|
+
const stripped = firstSegment.replace(/[0-9]+$/u, '');
|
|
105
|
+
if (stripped.length === 0)
|
|
106
|
+
return 'operator';
|
|
107
|
+
return stripped.charAt(0).toUpperCase() + stripped.slice(1);
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Resolve the model display string. Priority:
|
|
111
|
+
*
|
|
112
|
+
* 1. `PUGI_ENGINE_MODEL_CODE` env override (operator-set in shell).
|
|
113
|
+
* 2. `.pugi/settings.json` → `defaultModel` field (per-workspace).
|
|
114
|
+
* 3. Locked α7 default `"Sonnet 4.6 (1M context)"`.
|
|
115
|
+
*
|
|
116
|
+
* Returns the value verbatim — the banner is responsible for trimming
|
|
117
|
+
* if the string is too long for the column.
|
|
118
|
+
*/
|
|
119
|
+
export function resolveModelDisplay(env, settingsOverride) {
|
|
120
|
+
const envModel = env.PUGI_ENGINE_MODEL_CODE;
|
|
121
|
+
if (typeof envModel === 'string' && envModel.length > 0)
|
|
122
|
+
return envModel;
|
|
123
|
+
const settingsModel = settingsOverride?.defaultModel;
|
|
124
|
+
if (typeof settingsModel === 'string' && settingsModel.length > 0) {
|
|
125
|
+
return settingsModel;
|
|
126
|
+
}
|
|
127
|
+
return 'Sonnet 4.6 (1M context)';
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Locate the bundled CHANGELOG.md. The CLI ships к
|
|
131
|
+
* `node_modules/@pugi/cli/dist/tui/welcome-data.js` so the changelog
|
|
132
|
+
* lives at `node_modules/@pugi/cli/CHANGELOG.md` — two directory hops
|
|
133
|
+
* up from this file. In a local pnpm dev checkout the structure is the
|
|
134
|
+
* same (`src/tui/` ⇒ `../../CHANGELOG.md`) because tsx re-resolves the
|
|
135
|
+
* same relative tree.
|
|
136
|
+
*/
|
|
137
|
+
function defaultChangelogPath() {
|
|
138
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
139
|
+
return resolvePath(here, '..', '..', 'CHANGELOG.md');
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Read top-3 "what's new" headlines from the CLI CHANGELOG.md. Each
|
|
143
|
+
* headline is `<version> — <first non-empty section body line>` trimmed
|
|
144
|
+
* к 60 chars so the right column does not wrap on a 100-col terminal.
|
|
145
|
+
* Returns an empty array when the file is missing / unparseable.
|
|
146
|
+
*
|
|
147
|
+
* The body-line heuristic walks к the first non-empty, non-section-
|
|
148
|
+
* header line below the version header. For Keep-a-Changelog entries
|
|
149
|
+
* the second line is usually `### Added` / `### Fixed`; we skip those
|
|
150
|
+
* headers и land on the first bullet, which is the operator-visible
|
|
151
|
+
* one-liner ("- L30 `pugi theme` ...").
|
|
152
|
+
*/
|
|
153
|
+
export function readWhatsNew(changelogPath) {
|
|
154
|
+
const path = changelogPath ?? defaultChangelogPath();
|
|
155
|
+
try {
|
|
156
|
+
if (!existsSync(path))
|
|
157
|
+
return [];
|
|
158
|
+
const raw = readFileSync(path, 'utf8');
|
|
159
|
+
if (!raw || raw.length === 0)
|
|
160
|
+
return [];
|
|
161
|
+
const sections = parseChangelog(raw);
|
|
162
|
+
const headlines = [];
|
|
163
|
+
for (const section of sections) {
|
|
164
|
+
if (headlines.length >= 3)
|
|
165
|
+
break;
|
|
166
|
+
// Skip the "[Unreleased]" / "[Unreleased] - YYYY-MM-DD" section —
|
|
167
|
+
// the banner is meant к surface SHIPPED notes only. The parser
|
|
168
|
+
// captures Unreleased identically к а tagged version, so we
|
|
169
|
+
// filter here.
|
|
170
|
+
if (/^unreleased$/i.test(section.version))
|
|
171
|
+
continue;
|
|
172
|
+
const firstBullet = pickFirstBullet(section.body);
|
|
173
|
+
if (!firstBullet)
|
|
174
|
+
continue;
|
|
175
|
+
const headline = `${section.version} — ${firstBullet}`;
|
|
176
|
+
headlines.push(truncate(headline, 60));
|
|
177
|
+
}
|
|
178
|
+
return headlines;
|
|
179
|
+
}
|
|
180
|
+
catch {
|
|
181
|
+
return [];
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Pull the first bullet text out of a Keep-a-Changelog section body.
|
|
186
|
+
* Skips `### <subsection>` headers, blank lines, и non-bullet prose
|
|
187
|
+
* (release-note footers like "### Notes"). Returns undefined when no
|
|
188
|
+
* bullet is present.
|
|
189
|
+
*
|
|
190
|
+
* Body lines arrive verbatim from the parser; bullets follow the
|
|
191
|
+
* `- ` / `* ` Markdown convention. We strip the leading bullet glyph
|
|
192
|
+
* + the first whitespace run so the rendered string is the bullet
|
|
193
|
+
* content only.
|
|
194
|
+
*/
|
|
195
|
+
function pickFirstBullet(body) {
|
|
196
|
+
const lines = body.split('\n');
|
|
197
|
+
for (const line of lines) {
|
|
198
|
+
const trimmed = line.trim();
|
|
199
|
+
if (trimmed.length === 0)
|
|
200
|
+
continue;
|
|
201
|
+
if (trimmed.startsWith('### '))
|
|
202
|
+
continue;
|
|
203
|
+
if (trimmed.startsWith('- ') || trimmed.startsWith('* ')) {
|
|
204
|
+
// Strip leading bullet glyph + ws and collapse internal MD ticks.
|
|
205
|
+
return trimmed
|
|
206
|
+
.slice(2)
|
|
207
|
+
.replace(/`/g, '')
|
|
208
|
+
.replace(/\*\*/g, '')
|
|
209
|
+
.trim();
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
return undefined;
|
|
213
|
+
}
|
|
214
|
+
function truncate(text, max) {
|
|
215
|
+
if (text.length <= max)
|
|
216
|
+
return text;
|
|
217
|
+
// Reserve 1 char for the ellipsis so we land on EXACTLY `max`
|
|
218
|
+
// visible chars including the dot. Single Unicode ellipsis would be
|
|
219
|
+
// narrower but some terminals render it as а full-width glyph in
|
|
220
|
+
// CJK locales — ASCII three-dot stays predictable.
|
|
221
|
+
return `${text.slice(0, max - 1).trimEnd()}…`;
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Resolve the active credential and decode the JWT principal. Returns
|
|
225
|
+
* the email / tenant / plan triple when authenticated, null fields when
|
|
226
|
+
* anonymous. Encapsulates the credential + JWT IO so the spec can drive
|
|
227
|
+
* the resolver via an env override.
|
|
228
|
+
*/
|
|
229
|
+
function resolvePrincipal(env, home) {
|
|
230
|
+
const credential = resolveActiveCredential(env, home);
|
|
231
|
+
if (!credential) {
|
|
232
|
+
const file = readCredentialsFile(home);
|
|
233
|
+
return {
|
|
234
|
+
apiUrl: normalizeApiUrl(env.PUGI_API_URL ?? file.activeApiUrl ?? DEFAULT_API_URL),
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
const principal = decodeJwtPayload(credential.apiKey);
|
|
238
|
+
return {
|
|
239
|
+
apiUrl: credential.apiUrl,
|
|
240
|
+
...(principal?.email && { email: principal.email }),
|
|
241
|
+
...(principal?.customerId && { tenant: principal.customerId }),
|
|
242
|
+
...(principal?.plan && { plan: principal.plan }),
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Best-effort read of `.pugi/settings.json`. Returns null when the file
|
|
247
|
+
* is missing / unreadable / malformed so the model resolver can fall
|
|
248
|
+
* back to the env override + locked default.
|
|
249
|
+
*/
|
|
250
|
+
function readSettingsBlob(cwd) {
|
|
251
|
+
try {
|
|
252
|
+
const path = resolvePath(cwd, '.pugi', 'settings.json');
|
|
253
|
+
if (!existsSync(path))
|
|
254
|
+
return null;
|
|
255
|
+
const raw = readFileSync(path, 'utf8');
|
|
256
|
+
if (!raw || raw.length === 0)
|
|
257
|
+
return null;
|
|
258
|
+
const obj = JSON.parse(raw);
|
|
259
|
+
if (typeof obj?.defaultModel === 'string') {
|
|
260
|
+
return { defaultModel: obj.defaultModel };
|
|
261
|
+
}
|
|
262
|
+
return {};
|
|
263
|
+
}
|
|
264
|
+
catch {
|
|
265
|
+
return null;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
/* ------------------------------------------------------------------ */
|
|
269
|
+
/* Entry point */
|
|
270
|
+
/* ------------------------------------------------------------------ */
|
|
271
|
+
export function collectWelcomeData(input) {
|
|
272
|
+
const env = input.env ?? process.env;
|
|
273
|
+
const home = input.home ?? homedir();
|
|
274
|
+
const cwd = input.cwd ?? process.cwd();
|
|
275
|
+
const principal = resolvePrincipal(env, home);
|
|
276
|
+
const settings = input.settingsOverride !== undefined
|
|
277
|
+
? input.settingsOverride
|
|
278
|
+
: readSettingsBlob(cwd);
|
|
279
|
+
const greetingName = deriveGreetingName(principal.email);
|
|
280
|
+
const model = resolveModelDisplay(env, settings);
|
|
281
|
+
const whatsNew = readWhatsNew(input.changelogPath);
|
|
282
|
+
return {
|
|
283
|
+
greetingName,
|
|
284
|
+
...(principal.email && { email: principal.email }),
|
|
285
|
+
...(principal.tenant && { tenant: principal.tenant }),
|
|
286
|
+
...(principal.plan && { plan: principal.plan }),
|
|
287
|
+
model,
|
|
288
|
+
cwd,
|
|
289
|
+
cliVersion: input.cliVersion,
|
|
290
|
+
whatsNew,
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
//# sourceMappingURL=welcome-data.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pugi/cli",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.51",
|
|
4
4
|
"description": "Pugi CLI - terminal-native software execution system",
|
|
5
5
|
"homepage": "https://pugi.io",
|
|
6
6
|
"repository": {
|
|
@@ -29,8 +29,11 @@
|
|
|
29
29
|
"bin/run.js",
|
|
30
30
|
"dist/**/*.js",
|
|
31
31
|
"assets/**/*.ansi",
|
|
32
|
+
"docs/examples/**/*.json",
|
|
33
|
+
"test/scenarios/**/*.scenario.txt",
|
|
32
34
|
"README.md",
|
|
33
|
-
"LICENSE"
|
|
35
|
+
"LICENSE",
|
|
36
|
+
"THIRD_PARTY_NOTICES.md"
|
|
34
37
|
],
|
|
35
38
|
"engines": {
|
|
36
39
|
"node": ">=22.5.0"
|
|
@@ -46,13 +49,13 @@
|
|
|
46
49
|
"ink": "^5.0.1",
|
|
47
50
|
"linkedom": "^0.18.12",
|
|
48
51
|
"react": "^18.3.1",
|
|
49
|
-
"tar": "^
|
|
52
|
+
"tar": "^7.5.11",
|
|
50
53
|
"tinyglobby": "^0.2.16",
|
|
51
54
|
"turndown": "^7.2.4",
|
|
52
55
|
"undici": "^8.3.0",
|
|
53
56
|
"zod": "^3.23.0",
|
|
54
|
-
"@pugi/
|
|
55
|
-
"@pugi/
|
|
57
|
+
"@pugi/sdk": "0.1.0-beta.51",
|
|
58
|
+
"@pugi/personas": "0.1.2"
|
|
56
59
|
},
|
|
57
60
|
"devDependencies": {
|
|
58
61
|
"@types/node": "^22.0.0",
|
|
@@ -67,9 +70,12 @@
|
|
|
67
70
|
"build": "pnpm --filter @pugi/personas --filter @pugi/sdk build && tsc -p tsconfig.json && node scripts/make-bin-executable.mjs",
|
|
68
71
|
"dev": "tsx src/index.ts",
|
|
69
72
|
"typecheck": "pnpm --filter @pugi/personas --filter @pugi/sdk build && tsc -p tsconfig.json --noEmit",
|
|
70
|
-
"test": "pnpm run build && node --test --import tsx 'test/**/*.spec.ts' 'test/**/*.spec.tsx'",
|
|
73
|
+
"test": "pnpm run check:version-lockstep && pnpm run build && node --test --import tsx 'test/**/*.spec.ts' 'test/**/*.spec.tsx' 'src/**/*.spec.ts' 'src/**/*.spec.tsx'",
|
|
74
|
+
"test:integration": "INTEGRATION=1 pnpm run build && node --test --import tsx 'test/**/*.spec.ts' 'test/**/*.spec.tsx' 'src/**/*.spec.ts' 'src/**/*.spec.tsx'",
|
|
71
75
|
"version:cli": "tsx src/index.ts version",
|
|
72
76
|
"doctor": "tsx src/index.ts doctor --json",
|
|
73
|
-
"
|
|
77
|
+
"check:version-lockstep": "bash ../../scripts/check-version-lockstep.sh",
|
|
78
|
+
"pack:smoke": "pnpm run check:version-lockstep && node scripts/pack-smoke.mjs",
|
|
79
|
+
"release-gate": "node scripts/secret-scanner.mjs"
|
|
74
80
|
}
|
|
75
81
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# scenario: codegen-create-file
|
|
2
|
+
# title: Pugi actually writes a file (not just describes it)
|
|
3
|
+
|
|
4
|
+
# Anti-regression for task #265 — Pugi must call Write, not describe what
|
|
5
|
+
# it would write. The headless stub responder parses
|
|
6
|
+
# "create FILE with content 'TEXT'" and runs the real fs write so the
|
|
7
|
+
# scenario validates the wiring end-to-end. When Phase 2 lands the live
|
|
8
|
+
# engine path the same scenario carries over verbatim.
|
|
9
|
+
|
|
10
|
+
> "create hello.txt with content 'hello world'"
|
|
11
|
+
EXPECT: tool-call kind=Write file=hello.txt
|
|
12
|
+
EXPECT: persona-turn contains "wrote hello.txt"
|
|
13
|
+
EXPECT_FILE: hello.txt exists with content "hello world"
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# scenario: compact-force
|
|
2
|
+
# title: /compact --force is acknowledged
|
|
3
|
+
|
|
4
|
+
# Phase 1: the stub responder echoes the directive verbatim — Phase 2
|
|
5
|
+
# wires the slash command through to the live compaction loop. Until
|
|
6
|
+
# then this scenario protects the contract between scenario authoring
|
|
7
|
+
# and the harness envelope shape.
|
|
8
|
+
|
|
9
|
+
> "/compact --force"
|
|
10
|
+
EXPECT: persona-turn contains "/compact"
|
|
11
|
+
EXPECT_NOT: persona-turn contains "Mira"
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# scenario: identity
|
|
2
|
+
# title: Pugi self-identifies as Pugi (never as Mira)
|
|
3
|
+
|
|
4
|
+
# CEO directive feedback_live_console_test_every_publish: every published
|
|
5
|
+
# beta must still answer "ты кто?" with the Pugi persona, never the legacy
|
|
6
|
+
# Mira name. This is the single most-asked dialog in CEO dogfood and the
|
|
7
|
+
# regression that has bitten us most often.
|
|
8
|
+
|
|
9
|
+
> "ты кто?"
|
|
10
|
+
EXPECT: persona-turn contains "Pugi" OR "Пуджи"
|
|
11
|
+
EXPECT_NOT: persona-turn contains "Mira" OR "Мира"
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# scenario: persona-handoff
|
|
2
|
+
# title: Pugi hands off to Hiroshi when the operator asks for dev work
|
|
3
|
+
|
|
4
|
+
# Phase 1: the headless stub currently echoes input via the Pugi persona
|
|
5
|
+
# (real dispatch routing wires in Phase 2). The scenario is authored
|
|
6
|
+
# against the Phase 2 contract — for now it documents the intent and
|
|
7
|
+
# the harness keeps it as a soft EXPECT so the corpus stays loadable.
|
|
8
|
+
|
|
9
|
+
> "Hiroshi, please review the authentication module"
|
|
10
|
+
EXPECT: persona-turn contains "Pugi" OR "Hiroshi" OR "Хироси"
|
|
11
|
+
EXPECT_NOT: persona-turn contains "Mira"
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# scenario: walkback
|
|
2
|
+
# title: Esc-Esc walkback / rewind directive recognized
|
|
3
|
+
|
|
4
|
+
# CEO parity ask (BIG TRACK 8): the operator must be able to walk back
|
|
5
|
+
# the last turn. Phase 1 ships the harness contract — the live walkback
|
|
6
|
+
# wiring lands in BIG TRACK 8. The scenario asserts the stub responder
|
|
7
|
+
# acknowledges the directive verbatim so the contract holds while the
|
|
8
|
+
# real implementation lands behind it.
|
|
9
|
+
|
|
10
|
+
> "/rewind 1"
|
|
11
|
+
EXPECT: persona-turn contains "/rewind"
|
|
12
|
+
EXPECT_NOT: persona-turn contains "Mira"
|
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Engine loop integration point for the six-tier compaction engine.
|
|
3
|
-
*
|
|
4
|
-
* `maybeCompactAfterTool` is the single function the engine loop calls
|
|
5
|
-
* after each tool result has been appended to the transcript. It:
|
|
6
|
-
*
|
|
7
|
-
* 1. Estimates current context-window pressure (transcript bytes
|
|
8
|
-
* against the model's budget, plus the static blocks).
|
|
9
|
-
* 2. Calls `selectTier` on the snapshot.
|
|
10
|
-
* 3. Runs the tier. Microcompact / cached_microcompact are sync;
|
|
11
|
-
* reactive_summary / session_memory / full_compaction / reset
|
|
12
|
-
* are async-shaped (the call returns before commit when run
|
|
13
|
-
* against a long transcript) but currently run inline — the
|
|
14
|
-
* engine loop is single-threaded today, so true backgrounding
|
|
15
|
-
* waits for the SSE consumer refactor in α5.7.
|
|
16
|
-
* 4. Runs invariant checks against the result. On any violation,
|
|
17
|
-
* emits `compaction.invariant_violated` and returns the
|
|
18
|
-
* pre-compaction transcript untouched.
|
|
19
|
-
* 5. On success, emits `compaction.completed` with reclaim numbers
|
|
20
|
-
* and returns the new transcript for the caller to adopt.
|
|
21
|
-
* 6. On no-op, emits `compaction.skipped` and returns the original.
|
|
22
|
-
*
|
|
23
|
-
* Why a separate file (not inlined into `native-pugi.ts`):
|
|
24
|
-
*
|
|
25
|
-
* Sprint α5.3 (feat/pugi-cli-hooks-lifecycle-m1-gap-c) is in flight
|
|
26
|
-
* and already modifies session.ts + tool-bridge + permission. Editing
|
|
27
|
-
* native-pugi.ts in this PR risks a merge conflict against α5.3's
|
|
28
|
-
* landing PR. Keeping the wiring as an exported helper means the
|
|
29
|
-
* one-line callsite in native-pugi.ts can be added in a tiny
|
|
30
|
-
* follow-up after both α5.3 and α5.5 have landed.
|
|
31
|
-
*
|
|
32
|
-
* Expected callsite in `apps/pugi-cli/src/core/engine/native-pugi.ts`,
|
|
33
|
-
* inside `onToolResult`:
|
|
34
|
-
*
|
|
35
|
-
* ```ts
|
|
36
|
-
* const compactionOutcome = await maybeCompactAfterTool({
|
|
37
|
-
* session,
|
|
38
|
-
* transcript: currentTranscript,
|
|
39
|
-
* toolOutputs: recentToolOutputs,
|
|
40
|
-
* contextBudgetUsed: estimatedTokens,
|
|
41
|
-
* contextBudgetMax: budget.maxTokens,
|
|
42
|
-
* workspaceRoot: root,
|
|
43
|
-
* contextStaticHash: {
|
|
44
|
-
* instructionsHash,
|
|
45
|
-
* toolSchemaHash,
|
|
46
|
-
* },
|
|
47
|
-
* });
|
|
48
|
-
* if (compactionOutcome.committed) {
|
|
49
|
-
* currentTranscript = compactionOutcome.newTranscript;
|
|
50
|
-
* }
|
|
51
|
-
* ```
|
|
52
|
-
*/
|
|
53
|
-
import { runCompaction, selectTier, } from '../context/compaction.js';
|
|
54
|
-
import { checkInvariants } from '../context/invariants.js';
|
|
55
|
-
import { emitCompactionCompleted, emitCompactionInvariantViolated, emitCompactionSkipped, emitCompactionStarted, } from '../context/compaction-events.js';
|
|
56
|
-
/**
|
|
57
|
-
* Engine-loop callback. See file header for the expected callsite shape.
|
|
58
|
-
*
|
|
59
|
-
* Contract:
|
|
60
|
-
* - Never throws. All errors degrade to `committed: false` with the
|
|
61
|
-
* original transcript and an event record.
|
|
62
|
-
* - On `committed: true`, the caller MUST adopt `newTranscript` as
|
|
63
|
-
* the live working transcript for the next model turn.
|
|
64
|
-
* - On `committed: false`, the caller MUST keep the input transcript
|
|
65
|
-
* and try again on the next tool turn (compaction will retry once
|
|
66
|
-
* pressure stays above threshold).
|
|
67
|
-
*/
|
|
68
|
-
export async function maybeCompactAfterTool(input) {
|
|
69
|
-
const compactionInput = {
|
|
70
|
-
sessionId: input.session.id,
|
|
71
|
-
contextBudgetUsed: input.contextBudgetUsed,
|
|
72
|
-
contextBudgetMax: input.contextBudgetMax,
|
|
73
|
-
toolOutputs: input.toolOutputs,
|
|
74
|
-
transcript: input.transcript,
|
|
75
|
-
workspaceRoot: input.workspaceRoot,
|
|
76
|
-
};
|
|
77
|
-
const tier = selectTier(compactionInput);
|
|
78
|
-
emitCompactionStarted(input.session, tier, {
|
|
79
|
-
budgetUsed: input.contextBudgetUsed,
|
|
80
|
-
budgetMax: input.contextBudgetMax,
|
|
81
|
-
});
|
|
82
|
-
let result;
|
|
83
|
-
try {
|
|
84
|
-
result = await runCompaction(compactionInput, tier);
|
|
85
|
-
}
|
|
86
|
-
catch (error) {
|
|
87
|
-
const reason = error instanceof Error ? error.message : String(error);
|
|
88
|
-
emitCompactionSkipped(input.session, tier, `compaction crashed: ${reason}`);
|
|
89
|
-
return {
|
|
90
|
-
committed: false,
|
|
91
|
-
tier,
|
|
92
|
-
newTranscript: input.transcript,
|
|
93
|
-
bytesReclaimed: 0,
|
|
94
|
-
newContextSize: byteSize(input.transcript),
|
|
95
|
-
violations: [],
|
|
96
|
-
skipped: true,
|
|
97
|
-
skipReason: `crashed: ${reason}`,
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
if (result.skipped) {
|
|
101
|
-
emitCompactionSkipped(input.session, tier, result.skipReason || 'no work');
|
|
102
|
-
return {
|
|
103
|
-
committed: false,
|
|
104
|
-
tier,
|
|
105
|
-
newTranscript: input.transcript,
|
|
106
|
-
bytesReclaimed: 0,
|
|
107
|
-
newContextSize: byteSize(input.transcript),
|
|
108
|
-
violations: [],
|
|
109
|
-
skipped: true,
|
|
110
|
-
skipReason: result.skipReason,
|
|
111
|
-
};
|
|
112
|
-
}
|
|
113
|
-
// Invariant gate: static-hash-unchanged is enforced by passing the
|
|
114
|
-
// same hashes in for `before` and `after` — compaction never touches
|
|
115
|
-
// static blocks, so the hashes are equal by construction. We pass
|
|
116
|
-
// both so the contract is explicit; if a future tier introduces a
|
|
117
|
-
// bug that overwrites static state, the check still catches it.
|
|
118
|
-
const violations = checkInvariants({
|
|
119
|
-
before: compactionInput,
|
|
120
|
-
after: result,
|
|
121
|
-
summaryText: result.summaryText,
|
|
122
|
-
staticHashBefore: input.contextStaticHash,
|
|
123
|
-
staticHashAfter: input.contextStaticHash,
|
|
124
|
-
});
|
|
125
|
-
if (violations.length > 0) {
|
|
126
|
-
for (const v of violations)
|
|
127
|
-
emitCompactionInvariantViolated(input.session, v);
|
|
128
|
-
return {
|
|
129
|
-
committed: false,
|
|
130
|
-
tier,
|
|
131
|
-
newTranscript: input.transcript,
|
|
132
|
-
bytesReclaimed: 0,
|
|
133
|
-
newContextSize: byteSize(input.transcript),
|
|
134
|
-
violations,
|
|
135
|
-
skipped: false,
|
|
136
|
-
skipReason: '',
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
|
-
emitCompactionCompleted(input.session, tier, result.bytesReclaimed, result.newContextSize, result.artifactsCreated);
|
|
140
|
-
return {
|
|
141
|
-
committed: true,
|
|
142
|
-
tier,
|
|
143
|
-
newTranscript: result.newTranscript,
|
|
144
|
-
bytesReclaimed: result.bytesReclaimed,
|
|
145
|
-
newContextSize: result.newContextSize,
|
|
146
|
-
violations: [],
|
|
147
|
-
skipped: false,
|
|
148
|
-
skipReason: '',
|
|
149
|
-
};
|
|
150
|
-
}
|
|
151
|
-
function byteSize(transcript) {
|
|
152
|
-
return transcript.reduce((sum, t) => sum + Buffer.byteLength(t.content, 'utf8'), 0);
|
|
153
|
-
}
|
|
154
|
-
//# sourceMappingURL=compaction-hook.js.map
|