@pi-unipi/unipi 3.0.0-alpha.2 โ 3.0.0-alpha.21
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 +292 -0
- package/README.md +8 -11
- package/docs/prefix-cache-architecture.md +14 -0
- package/package.json +22 -24
- package/packages/ask-user/README.md +55 -107
- package/packages/ask-user/ask-ui.ts +306 -732
- package/packages/ask-user/clipboard.ts +50 -0
- package/packages/ask-user/config.ts +74 -78
- package/packages/ask-user/package.json +2 -2
- package/packages/ask-user/questions.ts +151 -0
- package/packages/ask-user/skills/ask-user/SKILL.md +59 -133
- package/packages/ask-user/tools.ts +198 -432
- package/packages/autocomplete/package.json +1 -1
- package/packages/autocomplete/src/constants.ts +38 -43
- package/packages/autocomplete/src/sorting.ts +8 -0
- package/packages/background-tasks/package.json +2 -2
- package/packages/background-tasks/src/config.ts +0 -73
- package/packages/background-tasks/src/index.ts +20 -16
- package/packages/background-tasks/src/registry.ts +1 -171
- package/packages/background-tasks/src/types.ts +0 -32
- package/packages/btw/README.md +13 -56
- package/packages/btw/extensions/btw.ts +403 -1796
- package/packages/btw/package.json +5 -2
- package/packages/btw/skills/btw/SKILL.md +7 -143
- package/packages/compactor/README.md +56 -287
- package/packages/compactor/package.json +5 -9
- package/packages/compactor/skills/compactor/SKILL.md +13 -20
- package/packages/compactor/src/card.ts +90 -0
- package/packages/compactor/src/commands/index.ts +73 -130
- package/packages/compactor/src/compaction/compact-args.ts +5 -3
- package/packages/compactor/src/compaction/filter-noise.ts +1 -1
- package/packages/compactor/src/compaction/hooks.ts +487 -311
- package/packages/compactor/src/compaction/source.ts +178 -0
- package/packages/compactor/src/compaction/summarize.ts +586 -52
- package/packages/compactor/src/config/manager.ts +130 -127
- package/packages/compactor/src/config/schema.ts +32 -48
- package/packages/compactor/src/index.ts +40 -431
- package/packages/compactor/src/info-screen.ts +44 -190
- package/packages/compactor/src/session/recall-blocks.ts +1 -1
- package/packages/compactor/src/stats.ts +76 -0
- package/packages/compactor/src/tools/context-budget.ts +17 -34
- package/packages/compactor/src/tools/ctx-doctor.ts +45 -36
- package/packages/compactor/src/tools/register.ts +29 -269
- package/packages/compactor/src/types.ts +47 -186
- package/packages/core/README.md +25 -0
- package/packages/core/child-agent.ts +1 -0
- package/packages/core/command-echo.ts +63 -0
- package/packages/core/compaction-context.ts +41 -0
- package/packages/core/constants.ts +8 -38
- package/packages/core/events.ts +0 -53
- package/packages/core/fusion-status.ts +4 -0
- package/packages/core/global.d.ts +10 -0
- package/packages/core/harness-messages.ts +392 -0
- package/packages/core/index.ts +14 -0
- package/packages/core/kanboard-status.ts +49 -0
- package/packages/core/long-horizon-owner-status.ts +46 -0
- package/packages/core/model-cache.ts +81 -7
- package/packages/core/package.json +6 -3
- package/packages/core/src/attach/detect.ts +163 -0
- package/packages/core/src/child-agent/child-args.ts +31 -0
- package/packages/core/src/child-agent/delivery.ts +41 -0
- package/packages/core/src/child-agent/index.ts +5 -0
- package/packages/core/src/child-agent/readers.ts +203 -0
- package/packages/core/src/child-agent/runtime.ts +584 -0
- package/packages/core/src/evidence.ts +78 -0
- package/packages/core/src/hints/browser.ts +278 -0
- package/packages/core/src/hints/crab-data.ts +19 -0
- package/packages/core/src/hints/index.ts +865 -0
- package/packages/core/src/hints/lines.ts +607 -0
- package/packages/core/src/hints/store.ts +120 -0
- package/packages/core/src/jev/chatter.ts +24 -0
- package/packages/core/src/jev/settings.ts +177 -14
- package/packages/core/src/package-colors.ts +2 -0
- package/packages/core/src/settings/catalog.ts +39 -15
- package/packages/core/src/settings/engine.ts +48 -2
- package/packages/core/src/settings/hub.ts +83 -20
- package/packages/core/src/settings/open.ts +49 -0
- package/packages/core/src/settings/schema.ts +27 -7
- package/packages/core/src/tui/hub-kit.ts +18 -5
- package/packages/core/src/tui/kit.ts +198 -0
- package/packages/core/src/tui/progress.ts +73 -0
- package/packages/core/src/turn/arbiter.ts +290 -0
- package/packages/footer/README.md +4 -6
- package/packages/footer/package.json +3 -3
- package/packages/footer/src/glance-editor.ts +19 -11
- package/packages/footer/src/help.ts +1 -1
- package/packages/footer/src/index.ts +36 -3
- package/packages/footer/src/presets.ts +3 -4
- package/packages/footer/src/rendering/icons.ts +0 -20
- package/packages/footer/src/segments/compactor.ts +52 -142
- package/packages/footer/src/segments/status-ext.ts +0 -1
- package/packages/fusion/README.md +14 -4
- package/packages/fusion/package.json +4 -3
- package/packages/fusion/src/child-args.ts +1 -0
- package/packages/fusion/src/index.ts +161 -8
- package/packages/fusion/src/pi-settings.ts +57 -0
- package/packages/fusion/src/picker.ts +186 -51
- package/packages/fusion/src/preset.ts +56 -2
- package/packages/fusion/src/prompts.ts +1 -1
- package/packages/fusion/src/sidekick-runtime.ts +1 -420
- package/packages/fusion/src/tools.ts +107 -128
- package/packages/fusion/src/transcript.ts +27 -85
- package/packages/info-screen/package.json +2 -2
- package/packages/input-shortcuts/README.md +18 -30
- package/packages/input-shortcuts/package.json +2 -2
- package/packages/input-shortcuts/src/burst.ts +88 -0
- package/packages/input-shortcuts/src/chord-overlay.ts +20 -70
- package/packages/input-shortcuts/src/cleared-input.ts +97 -0
- package/packages/input-shortcuts/src/index.ts +99 -193
- package/packages/input-shortcuts/src/last-response.ts +40 -0
- package/packages/input-shortcuts/src/registers.ts +8 -23
- package/packages/input-shortcuts/src/types.ts +4 -16
- package/packages/input-shortcuts/src/undo-redo.ts +59 -47
- package/packages/kanboard/README.md +51 -47
- package/packages/kanboard/index.ts +293 -55
- package/packages/kanboard/package.json +8 -8
- package/packages/kanboard/skills/kanboard/SKILL.md +61 -27
- package/packages/kanboard/src/badges.ts +93 -0
- package/packages/kanboard/src/bin.ts +4 -2
- package/packages/kanboard/src/commands.ts +218 -84
- package/packages/kanboard/src/debug.ts +20 -0
- package/packages/kanboard/src/guard.ts +267 -109
- package/packages/kanboard/src/monitor.ts +330 -0
- package/packages/kanboard/src/notice-buffer.ts +74 -0
- package/packages/kanboard/src/progress.ts +27 -0
- package/packages/kanboard/src/reminders.ts +234 -0
- package/packages/kanboard/src/settings.ts +69 -15
- package/packages/kanboard/src/shapes.ts +5 -0
- package/packages/long-horizon/index.ts +190 -13
- package/packages/long-horizon/package.json +3 -3
- package/packages/long-horizon/src/commands.ts +103 -7
- package/packages/long-horizon/src/compaction-brief.ts +35 -0
- package/packages/long-horizon/src/engine/continuation.ts +84 -15
- package/packages/long-horizon/src/engine/goal-state.ts +64 -13
- package/packages/long-horizon/src/engine/nudge-stash.ts +71 -0
- package/packages/long-horizon/src/engine/ralph.ts +3 -2
- package/packages/long-horizon/src/engine/runaway.ts +68 -11
- package/packages/long-horizon/src/engine/verifier.ts +19 -0
- package/packages/long-horizon/src/gate.ts +37 -12
- package/packages/long-horizon/src/judge/resolve.ts +1 -0
- package/packages/long-horizon/src/owner.ts +35 -2
- package/packages/long-horizon/src/progress.ts +87 -0
- package/packages/long-horizon/src/prompts/goal.ts +1 -1
- package/packages/long-horizon/src/runtime.ts +172 -18
- package/packages/long-horizon/src/settings.ts +54 -39
- package/packages/long-horizon/src/tools/goal.ts +6 -0
- package/packages/long-horizon/src/tools/graph.ts +1 -1
- package/packages/long-horizon/src/tools/swarm.ts +3 -3
- package/packages/mcp/package.json +2 -2
- package/packages/memory/commands.ts +7 -2
- package/packages/memory/index.ts +210 -32
- package/packages/memory/package.json +3 -3
- package/packages/memory/save-session.ts +264 -0
- package/packages/memory/settings.ts +17 -0
- package/packages/memory/tools.ts +253 -203
- package/packages/notify/package.json +2 -2
- package/packages/skill-registry/README.md +53 -16
- package/packages/skill-registry/index.ts +230 -0
- package/packages/skill-registry/package.json +19 -8
- package/packages/skill-registry/src/editor.ts +206 -0
- package/packages/skill-registry/src/judge.ts +289 -0
- package/packages/skill-registry/src/registry.ts +87 -0
- package/packages/skill-registry/src/settings.ts +259 -0
- package/packages/skill-registry/src/vault.ts +80 -0
- package/packages/subagents/README.md +39 -119
- package/packages/subagents/package.json +6 -13
- package/packages/subagents/skills/subagents/SKILL.md +18 -42
- package/packages/subagents/src/agents.ts +213 -0
- package/packages/subagents/src/cards.ts +182 -0
- package/packages/subagents/src/index.ts +609 -1084
- package/packages/subagents/src/manager.ts +429 -0
- package/packages/subagents/src/profiles.ts +130 -0
- package/packages/subagents/src/transcript.ts +154 -0
- package/packages/subagents/src/ui.ts +389 -0
- package/packages/unipi/bundled.js +39756 -45569
- package/packages/unipi/index.ts +55 -10
- package/packages/updater/package.json +2 -2
- package/packages/utility/README.md +76 -69
- package/packages/utility/package.json +2 -2
- package/packages/utility/skills/image/SKILL.md +37 -0
- package/packages/utility/skills/utility/SKILL.md +17 -60
- package/packages/utility/src/answer/extract.ts +128 -0
- package/packages/utility/src/answer/index.ts +213 -0
- package/packages/utility/src/answer/reply.ts +133 -0
- package/packages/utility/src/answer/web.ts +167 -0
- package/packages/utility/src/attach/index.ts +205 -0
- package/packages/utility/src/commands.ts +38 -142
- package/packages/utility/src/diagnostics/engine.ts +50 -5
- package/packages/utility/src/image/index.ts +33 -0
- package/packages/utility/src/image/models.ts +221 -0
- package/packages/{image/src โ utility/src/image}/recognize.ts +2 -2
- package/packages/utility/src/image/settings.ts +178 -0
- package/packages/{image/src/image-source.ts โ utility/src/image/source.ts} +1 -1
- package/packages/utility/src/image/tools.ts +168 -0
- package/packages/utility/src/image/transports.ts +186 -0
- package/packages/utility/src/index.ts +68 -389
- package/packages/utility/src/lifecycle/cleanup.ts +116 -311
- package/packages/utility/src/rename/gate.ts +102 -0
- package/packages/utility/src/rename/index.ts +191 -0
- package/packages/utility/src/rename/session.ts +170 -0
- package/packages/utility/src/render/delegated.ts +285 -0
- package/packages/utility/src/render/harness.ts +683 -0
- package/packages/utility/src/render/parse.ts +156 -0
- package/packages/utility/src/render/pi-settings.ts +38 -0
- package/packages/utility/src/render/reply-bg.ts +307 -0
- package/packages/utility/src/render/simple.ts +724 -0
- package/packages/utility/src/render/spacing.ts +235 -0
- package/packages/utility/src/render/styled.ts +251 -0
- package/packages/utility/src/render/tools.ts +353 -0
- package/packages/utility/src/settings.ts +166 -233
- package/packages/utility/src/types.ts +1 -222
- package/packages/watchdog/index.ts +17 -6
- package/packages/watchdog/package.json +3 -3
- package/packages/watchdog/src/config.ts +3 -2
- package/packages/web-api/package.json +2 -2
- package/packages/workflow/README.md +3 -0
- package/packages/workflow/index.ts +0 -2
- package/packages/workflow/package.json +2 -2
- package/packages/workflow/src/permission/decide.ts +6 -4
- package/packages/workflow/src/permission/index.ts +17 -7
- package/packages/workflow/src/permission/settings.ts +39 -4
- package/packages/workflow/src/plan/index.ts +19 -4
- package/packages/background-tasks/extensions/delegate-child.ts +0 -1
- package/packages/background-tasks/src/context-parent-snapshot.ts +0 -142
- package/packages/background-tasks/src/context-token-budget.ts +0 -903
- package/packages/background-tasks/src/context-visible-conversation-v2.ts +0 -551
- package/packages/background-tasks/src/delegate/artifacts.ts +0 -487
- package/packages/background-tasks/src/delegate/budget.ts +0 -415
- package/packages/background-tasks/src/delegate/hook-contract-evidence.json +0 -18
- package/packages/background-tasks/src/delegate/hook-contract.ts +0 -154
- package/packages/background-tasks/src/delegate/launch.ts +0 -484
- package/packages/background-tasks/src/delegate/result-package.ts +0 -459
- package/packages/background-tasks/src/delegate/runner.ts +0 -430
- package/packages/background-tasks/src/delegate/seed.ts +0 -423
- package/packages/background-tasks/src/delegate/types.ts +0 -323
- package/packages/background-tasks/src/delegate-child-extension.ts +0 -978
- package/packages/background-tasks/src/delegate-extension.ts +0 -654
- package/packages/background-tasks/src/fixtures/delegate-context-incident.json +0 -17
- package/packages/compactor/skills/compactor-detail/SKILL.md +0 -116
- package/packages/compactor/skills/compactor-doctor/SKILL.md +0 -71
- package/packages/compactor/skills/compactor-stats/SKILL.md +0 -51
- package/packages/compactor/src/compaction/build-sections.ts +0 -76
- package/packages/compactor/src/compaction/extract/goals.ts +0 -36
- package/packages/compactor/src/compaction/extract/preferences.ts +0 -40
- package/packages/compactor/src/compaction/format.ts +0 -53
- package/packages/compactor/src/compaction/merge.ts +0 -143
- package/packages/compactor/src/config/presets.ts +0 -160
- package/packages/compactor/src/executor/executor.ts +0 -233
- package/packages/compactor/src/executor/runtime.ts +0 -115
- package/packages/compactor/src/security/evaluator.ts +0 -89
- package/packages/compactor/src/security/policy.ts +0 -96
- package/packages/compactor/src/security/scanner.ts +0 -65
- package/packages/compactor/src/session/auto-inject.ts +0 -60
- package/packages/compactor/src/session/db.ts +0 -325
- package/packages/compactor/src/session/extract.ts +0 -144
- package/packages/compactor/src/session/resume-inject.ts +0 -64
- package/packages/compactor/src/session/snapshot.ts +0 -327
- package/packages/compactor/src/tools/ctx-batch-execute.ts +0 -41
- package/packages/compactor/src/tools/ctx-execute-file.ts +0 -23
- package/packages/compactor/src/tools/ctx-execute.ts +0 -23
- package/packages/compactor/src/tools/ctx-stats.ts +0 -96
- package/packages/image/README.md +0 -99
- package/packages/image/package.json +0 -61
- package/packages/image/skills/image/SKILL.md +0 -76
- package/packages/image/src/generate.ts +0 -256
- package/packages/image/src/index.ts +0 -135
- package/packages/image/src/models.ts +0 -519
- package/packages/image/src/openai-images-api.ts +0 -282
- package/packages/image/src/register-providers.ts +0 -209
- package/packages/image/src/settings.ts +0 -173
- package/packages/image/src/tools.ts +0 -326
- package/packages/input-shortcuts/src/clipboard.ts +0 -119
- package/packages/kanboard/src/runner.ts +0 -817
- package/packages/skill-registry/skills/auto/SKILL.md +0 -465
- package/packages/skill-registry/skills/brainstorm/SKILL.md +0 -219
- package/packages/skill-registry/skills/chore-create/SKILL.md +0 -315
- package/packages/skill-registry/skills/chore-execute/SKILL.md +0 -314
- package/packages/skill-registry/skills/consolidate/SKILL.md +0 -142
- package/packages/skill-registry/skills/consultant/SKILL.md +0 -97
- package/packages/skill-registry/skills/debug/SKILL.md +0 -228
- package/packages/skill-registry/skills/document/SKILL.md +0 -120
- package/packages/skill-registry/skills/fix/SKILL.md +0 -212
- package/packages/skill-registry/skills/gather-context/SKILL.md +0 -145
- package/packages/skill-registry/skills/plan/SKILL.md +0 -231
- package/packages/skill-registry/skills/quick-fix/SKILL.md +0 -135
- package/packages/skill-registry/skills/quick-work/SKILL.md +0 -110
- package/packages/skill-registry/skills/research/SKILL.md +0 -251
- package/packages/skill-registry/skills/review-work/SKILL.md +0 -187
- package/packages/skill-registry/skills/scan-issues/SKILL.md +0 -195
- package/packages/skill-registry/skills/work/SKILL.md +0 -218
- package/packages/skill-registry/skills/worktree-create/SKILL.md +0 -69
- package/packages/skill-registry/skills/worktree-list/SKILL.md +0 -78
- package/packages/skill-registry/skills/worktree-merge/SKILL.md +0 -89
- package/packages/subagents/agents/delegate.md +0 -14
- package/packages/subagents/agents/oracle.md +0 -78
- package/packages/subagents/agents/researcher.md +0 -52
- package/packages/subagents/agents/reviewer.md +0 -80
- package/packages/subagents/agents/scout.md +0 -50
- package/packages/subagents/agents/worker.md +0 -59
- package/packages/subagents/prompts/council.md +0 -48
- package/packages/subagents/prompts/gather-context-and-clarify.md +0 -13
- package/packages/subagents/prompts/parallel-cleanup.md +0 -59
- package/packages/subagents/prompts/parallel-research.md +0 -50
- package/packages/subagents/prompts/parallel-review.md +0 -54
- package/packages/subagents/prompts/review-loop.md +0 -43
- package/packages/subagents/skills/council-mode/SKILL.md +0 -230
- package/packages/subagents/skills/subagents/references/constraints-and-recipes.md +0 -259
- package/packages/subagents/skills/subagents/references/execution-controls.md +0 -454
- package/packages/subagents/skills/subagents/references/management-authoring-rpc.md +0 -161
- package/packages/subagents/skills/subagents/references/multi-lane-orchestration.md +0 -39
- package/packages/subagents/skills/subagents/references/prompting-and-roles.md +0 -267
- package/packages/subagents/src/acceptance.ts +0 -331
- package/packages/subagents/src/agent-manager.ts +0 -405
- package/packages/subagents/src/agent-memory.ts +0 -300
- package/packages/subagents/src/agent-overrides.ts +0 -183
- package/packages/subagents/src/agent-runner.ts +0 -271
- package/packages/subagents/src/async-runner.ts +0 -422
- package/packages/subagents/src/authority-policy.ts +0 -47
- package/packages/subagents/src/budgets.ts +0 -285
- package/packages/subagents/src/child-safety.ts +0 -140
- package/packages/subagents/src/config.ts +0 -249
- package/packages/subagents/src/conversation-viewer.ts +0 -281
- package/packages/subagents/src/core-compat.ts +0 -94
- package/packages/subagents/src/custom-agents.ts +0 -343
- package/packages/subagents/src/file-system-retry.ts +0 -50
- package/packages/subagents/src/fleet-data.ts +0 -105
- package/packages/subagents/src/fleet-view.ts +0 -322
- package/packages/subagents/src/foreground-detach.ts +0 -59
- package/packages/subagents/src/fork-context.ts +0 -285
- package/packages/subagents/src/global.d.ts +0 -7
- package/packages/subagents/src/guide.ts +0 -129
- package/packages/subagents/src/mission-state.ts +0 -133
- package/packages/subagents/src/mission-store.ts +0 -436
- package/packages/subagents/src/output-limits.ts +0 -142
- package/packages/subagents/src/parity-types.ts +0 -315
- package/packages/subagents/src/pi-args.ts +0 -167
- package/packages/subagents/src/result-files.ts +0 -232
- package/packages/subagents/src/result-watcher.ts +0 -221
- package/packages/subagents/src/retained-children.ts +0 -176
- package/packages/subagents/src/run-fanout-budget.ts +0 -356
- package/packages/subagents/src/scheduled-runs.ts +0 -349
- package/packages/subagents/src/schemas.ts +0 -263
- package/packages/subagents/src/slash-commands.ts +0 -80
- package/packages/subagents/src/supervisor-channel.ts +0 -249
- package/packages/subagents/src/tool-handler.ts +0 -1144
- package/packages/subagents/src/types.ts +0 -238
- package/packages/subagents/src/widget.ts +0 -457
- package/packages/subagents/src/workflow-script.ts +0 -737
- package/packages/subagents/src/workflow-worker.ts +0 -384
- package/packages/subagents/src/worktree.ts +0 -614
- package/packages/utility/src/analytics/collector.ts +0 -293
- package/packages/utility/src/info-screen.ts +0 -80
- package/packages/utility/src/lifecycle/process.ts +0 -162
- package/packages/utility/src/prefix-cache.ts +0 -263
- package/packages/utility/src/skill-discovery.ts +0 -542
- package/packages/utility/src/tools/env.ts +0 -113
- package/packages/utility/src/tui/name-badge-state.ts +0 -315
- package/packages/utility/src/tui/name-badge.ts +0 -109
- /package/packages/{subagents/src โ core/src/child-agent}/pi-spawn.ts +0 -0
|
@@ -1,347 +1,152 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @pi-unipi/utility โ Stale
|
|
2
|
+
* @pi-unipi/utility โ Stale cleanup (allowlist only)
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Only the targets listed in TARGETS can ever be removed. Everything else
|
|
5
|
+
* under ~/.unipi โ memory, v2 backups, kanboard boards, config, workspace
|
|
6
|
+
* state โ is out of reach by construction, not by pattern luck. Callers
|
|
7
|
+
* preview first (`dryRun`) and delete only after the user confirms.
|
|
5
8
|
*/
|
|
6
9
|
|
|
7
|
-
import { existsSync,
|
|
8
|
-
import { join, resolve, basename } from "node:path";
|
|
10
|
+
import { existsSync, readdirSync, rmSync, statSync } from "node:fs";
|
|
9
11
|
import { homedir, tmpdir } from "node:os";
|
|
10
|
-
import
|
|
12
|
+
import { join } from "node:path";
|
|
13
|
+
|
|
14
|
+
export interface CleanupTarget {
|
|
15
|
+
id: string;
|
|
16
|
+
label: string;
|
|
17
|
+
/** Directory scanned (non-recursive). */
|
|
18
|
+
dir: () => string;
|
|
19
|
+
/** Entry names that belong to this target. */
|
|
20
|
+
match: RegExp;
|
|
21
|
+
/** Minimum age in days; 0 = any age (the feature that wrote it is gone). */
|
|
22
|
+
minAgeDays: number;
|
|
23
|
+
/** Entry kind to consider. */
|
|
24
|
+
kind: "file" | "dir" | "any";
|
|
25
|
+
}
|
|
11
26
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
27
|
+
const unipi = (...parts: string[]) => join(homedir(), ".unipi", ...parts);
|
|
28
|
+
|
|
29
|
+
export const TARGETS: readonly CleanupTarget[] = [
|
|
30
|
+
{
|
|
31
|
+
id: "tool-results",
|
|
32
|
+
label: "Saved tool outputs older than 7 days",
|
|
33
|
+
dir: () => unipi("tool-results"),
|
|
34
|
+
match: /^(?:tool-result|mcp-[a-zA-Z0-9_-]+|helper)-[a-f0-9-]+\.txt$/,
|
|
35
|
+
minAgeDays: 7,
|
|
36
|
+
kind: "file",
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
id: "temp",
|
|
40
|
+
label: "UniPi temp files older than 7 days",
|
|
41
|
+
dir: () => tmpdir(),
|
|
42
|
+
match: /^unipi-/,
|
|
43
|
+
minAgeDays: 7,
|
|
44
|
+
kind: "file",
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
id: "compactor-db",
|
|
48
|
+
label: "Old compactor continuity database (no longer used)",
|
|
49
|
+
dir: () => unipi("db"),
|
|
50
|
+
match: /^compactor$/,
|
|
51
|
+
minAgeDays: 0,
|
|
52
|
+
kind: "dir",
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
id: "compactor-db-global",
|
|
56
|
+
label: "Old compactor continuity database (no longer used)",
|
|
57
|
+
dir: () => unipi("global"),
|
|
58
|
+
match: /^compactor$/,
|
|
59
|
+
minAgeDays: 0,
|
|
60
|
+
kind: "dir",
|
|
61
|
+
},
|
|
62
|
+
];
|
|
63
|
+
|
|
64
|
+
export interface CleanupItem {
|
|
65
|
+
target: string;
|
|
66
|
+
path: string;
|
|
67
|
+
bytes: number;
|
|
68
|
+
}
|
|
19
69
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
return path;
|
|
70
|
+
export interface CleanupResult {
|
|
71
|
+
items: CleanupItem[];
|
|
72
|
+
removed: number;
|
|
73
|
+
bytes: number;
|
|
74
|
+
failed: string[];
|
|
26
75
|
}
|
|
27
76
|
|
|
28
|
-
|
|
29
|
-
function isStale(path: string, maxAgeDays: number): boolean {
|
|
77
|
+
function sizeOf(path: string): number {
|
|
30
78
|
try {
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
return
|
|
79
|
+
const st = statSync(path);
|
|
80
|
+
if (!st.isDirectory()) return st.size;
|
|
81
|
+
return readdirSync(path).reduce((sum, name) => sum + sizeOf(join(path, name)), 0);
|
|
34
82
|
} catch {
|
|
35
|
-
return
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/** Try to detect if a DB file has a zombie WAL lock */
|
|
40
|
-
function hasWalLock(dbPath: string): boolean {
|
|
41
|
-
const walPath = dbPath + "-wal";
|
|
42
|
-
const shmPath = dbPath + "-shm";
|
|
43
|
-
// If WAL exists but journal mode isn't WAL, or WAL is very old, it's stale
|
|
44
|
-
if (existsSync(walPath)) {
|
|
45
|
-
try {
|
|
46
|
-
const walStats = statSync(walPath);
|
|
47
|
-
const ageMs = Date.now() - walStats.mtime.getTime();
|
|
48
|
-
return ageMs > 5 * 60 * 1000; // 5 min = stale WAL
|
|
49
|
-
} catch {
|
|
50
|
-
return false;
|
|
51
|
-
}
|
|
83
|
+
return 0;
|
|
52
84
|
}
|
|
53
|
-
return false;
|
|
54
85
|
}
|
|
55
86
|
|
|
56
|
-
/**
|
|
57
|
-
function
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
const unipiDir = expandHome("~/.unipi");
|
|
66
|
-
if (!existsSync(unipiDir)) return result;
|
|
67
|
-
|
|
68
|
-
const scanDir = (dir: string) => {
|
|
69
|
-
let entries: string[];
|
|
87
|
+
/** Everything the allowlist would remove right now. Never deletes. */
|
|
88
|
+
export function findCleanupItems(targets: readonly CleanupTarget[] = TARGETS, now = Date.now()): CleanupItem[] {
|
|
89
|
+
const items: CleanupItem[] = [];
|
|
90
|
+
for (const target of targets) {
|
|
91
|
+
const dir = target.dir();
|
|
92
|
+
if (!existsSync(dir)) continue;
|
|
93
|
+
let names: string[];
|
|
70
94
|
try {
|
|
71
|
-
|
|
95
|
+
names = readdirSync(dir);
|
|
72
96
|
} catch {
|
|
73
|
-
|
|
97
|
+
continue;
|
|
74
98
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
const
|
|
99
|
+
for (const name of names) {
|
|
100
|
+
if (!target.match.test(name)) continue;
|
|
101
|
+
const path = join(dir, name);
|
|
78
102
|
try {
|
|
79
|
-
const
|
|
80
|
-
if (
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// Match SQLite DB files
|
|
86
|
-
if (
|
|
87
|
-
entry.endsWith(".db") ||
|
|
88
|
-
entry.endsWith(".sqlite") ||
|
|
89
|
-
entry.endsWith(".sqlite3")
|
|
90
|
-
) {
|
|
91
|
-
if (isStale(fullPath, options.dbMaxAgeDays) || hasWalLock(fullPath)) {
|
|
92
|
-
result.bytesFreed += stats.size;
|
|
93
|
-
result.paths.push(fullPath);
|
|
94
|
-
if (!options.dryRun) {
|
|
95
|
-
try {
|
|
96
|
-
unlinkSync(fullPath);
|
|
97
|
-
// Also clean WAL/SHM companions
|
|
98
|
-
for (const suffix of ["-wal", "-shm", "-journal"]) {
|
|
99
|
-
const companion = fullPath + suffix;
|
|
100
|
-
if (existsSync(companion)) {
|
|
101
|
-
unlinkSync(companion);
|
|
102
|
-
result.bytesFreed += statSync(companion).size;
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
result.removed++;
|
|
106
|
-
} catch {
|
|
107
|
-
// Best effort
|
|
108
|
-
}
|
|
109
|
-
} else {
|
|
110
|
-
result.removed++;
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
}
|
|
103
|
+
const st = statSync(path);
|
|
104
|
+
if (target.kind === "file" && !st.isFile()) continue;
|
|
105
|
+
if (target.kind === "dir" && !st.isDirectory()) continue;
|
|
106
|
+
if (target.minAgeDays > 0 && now - st.mtimeMs < target.minAgeDays * 86_400_000) continue;
|
|
107
|
+
items.push({ target: target.id, path, bytes: sizeOf(path) });
|
|
114
108
|
} catch {
|
|
115
|
-
//
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
scanDir(unipiDir);
|
|
121
|
-
return result;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
/** Clean private tool-result artifacts after the configured temp retention. */
|
|
125
|
-
function cleanToolResults(options: Required<CleanupOptions>): CleanupResult {
|
|
126
|
-
const result: CleanupResult = {
|
|
127
|
-
category: "tool-results",
|
|
128
|
-
removed: 0,
|
|
129
|
-
bytesFreed: 0,
|
|
130
|
-
paths: [],
|
|
131
|
-
};
|
|
132
|
-
const dir = expandHome("~/.unipi/tool-results");
|
|
133
|
-
if (!existsSync(dir)) return result;
|
|
134
|
-
|
|
135
|
-
let entries: string[];
|
|
136
|
-
try { entries = readdirSync(dir); } catch { return result; }
|
|
137
|
-
for (const entry of entries) {
|
|
138
|
-
if (!/^(?:tool-result|mcp-[a-zA-Z0-9_-]+|helper)-[a-f0-9-]+\.txt$/.test(entry)) continue;
|
|
139
|
-
const path = join(dir, entry);
|
|
140
|
-
try {
|
|
141
|
-
const stats = statSync(path);
|
|
142
|
-
if (!stats.isFile() || !isStale(path, options.tempMaxAgeDays)) continue;
|
|
143
|
-
result.paths.push(path);
|
|
144
|
-
result.bytesFreed += stats.size;
|
|
145
|
-
if (!options.dryRun) unlinkSync(path);
|
|
146
|
-
result.removed++;
|
|
147
|
-
} catch { /* best effort */ }
|
|
148
|
-
}
|
|
149
|
-
return result;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
/** Clean temp files matching unipi patterns */
|
|
153
|
-
function cleanTemps(options: Required<CleanupOptions>): CleanupResult {
|
|
154
|
-
const result: CleanupResult = {
|
|
155
|
-
category: "temp",
|
|
156
|
-
removed: 0,
|
|
157
|
-
bytesFreed: 0,
|
|
158
|
-
paths: [],
|
|
159
|
-
};
|
|
160
|
-
|
|
161
|
-
const patterns = [/^unipi-/, /^pi-/, /\.unipi\./];
|
|
162
|
-
const tmpDir = tmpdir();
|
|
163
|
-
|
|
164
|
-
let entries: string[];
|
|
165
|
-
try {
|
|
166
|
-
entries = readdirSync(tmpDir);
|
|
167
|
-
} catch {
|
|
168
|
-
return result;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
for (const entry of entries) {
|
|
172
|
-
if (!patterns.some((p) => p.test(entry))) continue;
|
|
173
|
-
|
|
174
|
-
const fullPath = join(tmpDir, entry);
|
|
175
|
-
try {
|
|
176
|
-
const stats = statSync(fullPath);
|
|
177
|
-
if (!stats.isFile()) continue;
|
|
178
|
-
|
|
179
|
-
if (isStale(fullPath, options.tempMaxAgeDays)) {
|
|
180
|
-
result.bytesFreed += stats.size;
|
|
181
|
-
result.paths.push(fullPath);
|
|
182
|
-
if (!options.dryRun) {
|
|
183
|
-
try {
|
|
184
|
-
unlinkSync(fullPath);
|
|
185
|
-
result.removed++;
|
|
186
|
-
} catch {
|
|
187
|
-
// Best effort
|
|
188
|
-
}
|
|
189
|
-
} else {
|
|
190
|
-
result.removed++;
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
} catch {
|
|
194
|
-
// Skip unreadable
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
return result;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
/** Clean stale session directories */
|
|
202
|
-
function cleanSessions(options: Required<CleanupOptions>): CleanupResult {
|
|
203
|
-
const result: CleanupResult = {
|
|
204
|
-
category: "session",
|
|
205
|
-
removed: 0,
|
|
206
|
-
bytesFreed: 0,
|
|
207
|
-
paths: [],
|
|
208
|
-
};
|
|
209
|
-
|
|
210
|
-
const unipiDir = expandHome("~/.unipi");
|
|
211
|
-
const sessionsDir = join(unipiDir, "sessions");
|
|
212
|
-
if (!existsSync(sessionsDir)) return result;
|
|
213
|
-
|
|
214
|
-
let entries: string[];
|
|
215
|
-
try {
|
|
216
|
-
entries = readdirSync(sessionsDir);
|
|
217
|
-
} catch {
|
|
218
|
-
return result;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
for (const entry of entries) {
|
|
222
|
-
const fullPath = join(sessionsDir, entry);
|
|
223
|
-
try {
|
|
224
|
-
const stats = statSync(fullPath);
|
|
225
|
-
if (!stats.isDirectory()) continue;
|
|
226
|
-
|
|
227
|
-
if (isStale(fullPath, options.sessionMaxAgeDays)) {
|
|
228
|
-
result.bytesFreed += stats.size;
|
|
229
|
-
result.paths.push(fullPath);
|
|
230
|
-
if (!options.dryRun) {
|
|
231
|
-
try {
|
|
232
|
-
rmSync(fullPath, { recursive: true, force: true });
|
|
233
|
-
result.removed++;
|
|
234
|
-
} catch {
|
|
235
|
-
// Best effort
|
|
236
|
-
}
|
|
237
|
-
} else {
|
|
238
|
-
result.removed++;
|
|
239
|
-
}
|
|
109
|
+
// Unreadable entry โ skip.
|
|
240
110
|
}
|
|
241
|
-
} catch {
|
|
242
|
-
// Skip unreadable
|
|
243
111
|
}
|
|
244
112
|
}
|
|
245
|
-
|
|
246
|
-
return result;
|
|
113
|
+
return items;
|
|
247
114
|
}
|
|
248
115
|
|
|
249
|
-
/**
|
|
250
|
-
function
|
|
251
|
-
const
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
paths: [],
|
|
256
|
-
};
|
|
257
|
-
|
|
258
|
-
const cacheDir = expandHome("~/.unipi/cache");
|
|
259
|
-
if (!existsSync(cacheDir)) return result;
|
|
260
|
-
|
|
261
|
-
let entries: string[];
|
|
262
|
-
try {
|
|
263
|
-
entries = readdirSync(cacheDir);
|
|
264
|
-
} catch {
|
|
265
|
-
return result;
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
for (const entry of entries) {
|
|
269
|
-
const fullPath = join(cacheDir, entry);
|
|
116
|
+
/** Delete exactly the previewed items (re-validated against the allowlist). */
|
|
117
|
+
export function removeCleanupItems(items: readonly CleanupItem[], targets: readonly CleanupTarget[] = TARGETS): CleanupResult {
|
|
118
|
+
const allowed = new Set(findCleanupItems(targets).map((i) => i.path));
|
|
119
|
+
const result: CleanupResult = { items: [...items], removed: 0, bytes: 0, failed: [] };
|
|
120
|
+
for (const item of items) {
|
|
121
|
+
if (!allowed.has(item.path)) continue;
|
|
270
122
|
try {
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
if (isStale(fullPath, options.tempMaxAgeDays)) {
|
|
275
|
-
result.bytesFreed += stats.size;
|
|
276
|
-
result.paths.push(fullPath);
|
|
277
|
-
if (!options.dryRun) {
|
|
278
|
-
try {
|
|
279
|
-
unlinkSync(fullPath);
|
|
280
|
-
result.removed++;
|
|
281
|
-
} catch {
|
|
282
|
-
// Best effort
|
|
283
|
-
}
|
|
284
|
-
} else {
|
|
285
|
-
result.removed++;
|
|
286
|
-
}
|
|
287
|
-
}
|
|
123
|
+
rmSync(item.path, { recursive: true, force: true });
|
|
124
|
+
result.removed++;
|
|
125
|
+
result.bytes += item.bytes;
|
|
288
126
|
} catch {
|
|
289
|
-
|
|
127
|
+
result.failed.push(item.path);
|
|
290
128
|
}
|
|
291
129
|
}
|
|
292
|
-
|
|
293
130
|
return result;
|
|
294
131
|
}
|
|
295
132
|
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
const opts: Required<CleanupOptions> = { ...DEFAULTS, ...options };
|
|
301
|
-
|
|
302
|
-
const results: CleanupResult[] = [
|
|
303
|
-
cleanDbs(opts),
|
|
304
|
-
cleanTemps(opts),
|
|
305
|
-
cleanToolResults(opts),
|
|
306
|
-
cleanSessions(opts),
|
|
307
|
-
cleanCache(opts),
|
|
308
|
-
];
|
|
309
|
-
|
|
310
|
-
return {
|
|
311
|
-
timestamp: Date.now(),
|
|
312
|
-
results,
|
|
313
|
-
totalRemoved: results.reduce((sum, r) => sum + r.removed, 0),
|
|
314
|
-
totalBytesFreed: results.reduce((sum, r) => sum + r.bytesFreed, 0),
|
|
315
|
-
};
|
|
133
|
+
export function formatBytes(bytes: number): string {
|
|
134
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
135
|
+
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
136
|
+
return `${(bytes / 1024 / 1024).toFixed(1)} MB`;
|
|
316
137
|
}
|
|
317
138
|
|
|
318
|
-
/**
|
|
319
|
-
export function
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
for (const result of report.results) {
|
|
330
|
-
if (result.removed === 0) continue;
|
|
331
|
-
lines.push(
|
|
332
|
-
`### ${result.category.toUpperCase()}`,
|
|
333
|
-
`- Removed: ${result.removed}`,
|
|
334
|
-
`- Freed: ${(result.bytesFreed / 1024).toFixed(1)} KB`,
|
|
335
|
-
"",
|
|
336
|
-
);
|
|
337
|
-
for (const path of result.paths.slice(0, 10)) {
|
|
338
|
-
lines.push(`- \`${path}\``);
|
|
339
|
-
}
|
|
340
|
-
if (result.paths.length > 10) {
|
|
341
|
-
lines.push(`- ... and ${result.paths.length - 10} more`);
|
|
342
|
-
}
|
|
343
|
-
lines.push("");
|
|
139
|
+
/** Preview grouped by target โ what the confirm dialog and dry run show. */
|
|
140
|
+
export function formatCleanupPreview(items: readonly CleanupItem[], targets: readonly CleanupTarget[] = TARGETS): string {
|
|
141
|
+
if (items.length === 0) return "Nothing to clean.";
|
|
142
|
+
const total = items.reduce((sum, i) => sum + i.bytes, 0);
|
|
143
|
+
const lines = [`${items.length} item(s), ${formatBytes(total)}:`];
|
|
144
|
+
for (const target of targets) {
|
|
145
|
+
const mine = items.filter((i) => i.target === target.id);
|
|
146
|
+
if (mine.length === 0) continue;
|
|
147
|
+
lines.push(`- ${target.label}: ${mine.length} (${formatBytes(mine.reduce((s, i) => s + i.bytes, 0))})`);
|
|
148
|
+
for (const item of mine.slice(0, 5)) lines.push(` ${item.path}`);
|
|
149
|
+
if (mine.length > 5) lines.push(` โฆ and ${mine.length - 5} more`);
|
|
344
150
|
}
|
|
345
|
-
|
|
346
151
|
return lines.join("\n");
|
|
347
152
|
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @pi-unipi/utility โ Auto-rename gate
|
|
3
|
+
*
|
|
4
|
+
* Decides, after a confirmed round, whether the session deserves a (new) name.
|
|
5
|
+
* It judges the ROUND โ the user's message AND what the agent did with it โ so
|
|
6
|
+
* a vague opener ("hi, let's look at what we have") that turns into real work
|
|
7
|
+
* still names the session:
|
|
8
|
+
* 1. Cheap prefilter: a bare greeting/thanks/"ok" round with no tool work never renames.
|
|
9
|
+
* 2. jev, two local questions:
|
|
10
|
+
* request โ did the round establish a subject a title could describe?
|
|
11
|
+
* topic โ (only when named) did it move to a different task?
|
|
12
|
+
* 3. jev unavailable โ rename only an unnamed session after a round with
|
|
13
|
+
* real work (tool calls) or a โฅ4-word prompt.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { isChatter, type JevAnswer } from "@pi-unipi/core";
|
|
17
|
+
|
|
18
|
+
export { isChatter };
|
|
19
|
+
|
|
20
|
+
export function wordCount(text: string): number {
|
|
21
|
+
return text.trim().split(/\s+/).filter(Boolean).length;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface GateInput {
|
|
25
|
+
prompt: string;
|
|
26
|
+
currentName: string | null;
|
|
27
|
+
earlier: readonly string[];
|
|
28
|
+
/** The agent's final reply this round (trimmed). */
|
|
29
|
+
reply?: string;
|
|
30
|
+
/** Tool calls the agent made this round. */
|
|
31
|
+
toolCalls?: number;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** A round with this many tool calls did real work, whatever the prompt said. */
|
|
35
|
+
export const WORK_TOOL_CALLS = 2;
|
|
36
|
+
|
|
37
|
+
export function gateRequest(input: GateInput): { state: string; questions: Record<string, unknown> } {
|
|
38
|
+
const earlier = input.earlier.filter((e) => e !== input.prompt).slice(-3);
|
|
39
|
+
const state = [
|
|
40
|
+
`Latest user message:\n${input.prompt.slice(0, 1500)}`,
|
|
41
|
+
earlier.length ? `Earlier user messages:\n${earlier.map((e) => `- ${e.slice(0, 200)}`).join("\n")}` : "",
|
|
42
|
+
input.reply ? `Assistant's reply this round (${input.toolCalls ?? 0} tool calls):\n${input.reply.slice(0, 1200)}` : "",
|
|
43
|
+
input.currentName ? `Current session title: "${input.currentName}"` : "The session has no title yet.",
|
|
44
|
+
].filter(Boolean).join("\n\n");
|
|
45
|
+
const questions: Record<string, unknown> = {
|
|
46
|
+
request: {
|
|
47
|
+
type: "choice",
|
|
48
|
+
instructions: "Did this round (the latest user message together with the assistant's reply) establish a task or subject that a session title could describe?",
|
|
49
|
+
criteria: {
|
|
50
|
+
task: "The user asked for work, a change, an answer, a review or an investigation โ or opened loosely and the assistant's reply shows real work on a definite subject.",
|
|
51
|
+
chatter: "Only small talk: a greeting, thanks, acknowledgement, approval (yes / ok / go on) or a bare 'continue', and the reply adds no subject of its own.",
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
if (input.currentName) {
|
|
56
|
+
questions.topic = {
|
|
57
|
+
type: "choice",
|
|
58
|
+
instructions: `Does this round move to a different task than the current title "${input.currentName}"?`,
|
|
59
|
+
criteria: {
|
|
60
|
+
same: "Same task or area: a follow-up, refinement, fix or next step of what the title describes.",
|
|
61
|
+
new: "A different task, feature or subject that the current title no longer describes.",
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
return { state, questions };
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export const REQUEST_CONFIDENCE = 0.6;
|
|
69
|
+
export const TOPIC_CONFIDENCE = 0.7;
|
|
70
|
+
|
|
71
|
+
export type GateDecision = { rename: true; reason: string } | { rename: false; reason: string };
|
|
72
|
+
|
|
73
|
+
/** Rounds that can never name a session, decided without jev. */
|
|
74
|
+
export function isIdleRound(input: GateInput): boolean {
|
|
75
|
+
return isChatter(input.prompt) && (input.toolCalls ?? 0) < WORK_TOOL_CALLS;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function decide(input: GateInput, answers: Record<string, JevAnswer> | null): GateDecision {
|
|
79
|
+
if (isIdleRound(input)) return { rename: false, reason: "chatter" };
|
|
80
|
+
if (!answers) {
|
|
81
|
+
if (input.currentName) return { rename: false, reason: "jev unavailable; keeping current name" };
|
|
82
|
+
return wordCount(input.prompt) >= 4 || (input.toolCalls ?? 0) >= WORK_TOOL_CALLS
|
|
83
|
+
? { rename: true, reason: "jev unavailable; first substantive round" }
|
|
84
|
+
: { rename: false, reason: "jev unavailable; prompt too short" };
|
|
85
|
+
}
|
|
86
|
+
const req = answers.request;
|
|
87
|
+
if (req?.choice !== "task" || (req.confidence ?? 0) < REQUEST_CONFIDENCE) {
|
|
88
|
+
return { rename: false, reason: `not a request (${req?.choice ?? "?"} ${(req?.confidence ?? 0).toFixed(2)})` };
|
|
89
|
+
}
|
|
90
|
+
if (!input.currentName) return { rename: true, reason: "first request" };
|
|
91
|
+
const topic = answers.topic;
|
|
92
|
+
if (topic?.choice === "new" && (topic.confidence ?? 0) >= TOPIC_CONFIDENCE) {
|
|
93
|
+
return { rename: true, reason: `topic changed (${(topic.confidence ?? 0).toFixed(2)})` };
|
|
94
|
+
}
|
|
95
|
+
return { rename: false, reason: `same topic (${topic?.choice ?? "?"} ${(topic?.confidence ?? 0).toFixed(2)})` };
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/** Clean a model-proposed title: one line, no quotes, โค 6 words / 60 chars. */
|
|
99
|
+
export function sanitizeName(raw: string): string {
|
|
100
|
+
const line = raw.split("\n")[0]!.replace(/^["'`*#\s]+|["'`*\s.]+$/g, "").replace(/\s+/g, " ").trim();
|
|
101
|
+
return line.split(" ").slice(0, 6).join(" ").slice(0, 60).trim();
|
|
102
|
+
}
|