crispy-recall 0.2.0 → 0.3.0
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/README.md +230 -169
- package/THIRD-PARTY-LICENSES +43 -145
- package/dist/SKILL.md.template +7 -0
- package/dist/embed-pending.js +742 -204
- package/dist/recall.js +3029 -941
- package/dist/statusline.js +180 -0
- package/dist/stop-hook.js +611 -144
- package/package.json +3 -2
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __export = (target, all) => {
|
|
10
|
+
for (var name in all)
|
|
11
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
12
|
+
};
|
|
13
|
+
var __copyProps = (to, from, except, desc) => {
|
|
14
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
15
|
+
for (let key of __getOwnPropNames(from))
|
|
16
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
17
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
18
|
+
}
|
|
19
|
+
return to;
|
|
20
|
+
};
|
|
21
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
22
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
23
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
24
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
25
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
26
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
27
|
+
mod
|
|
28
|
+
));
|
|
29
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
30
|
+
|
|
31
|
+
// src/hooks/statusline.ts
|
|
32
|
+
var statusline_exports = {};
|
|
33
|
+
__export(statusline_exports, {
|
|
34
|
+
parseGitStatus: () => parseGitStatus
|
|
35
|
+
});
|
|
36
|
+
module.exports = __toCommonJS(statusline_exports);
|
|
37
|
+
var import_node_process = __toESM(require("node:process"));
|
|
38
|
+
var import_node_child_process = require("node:child_process");
|
|
39
|
+
|
|
40
|
+
// src/recall/statusline-segment.ts
|
|
41
|
+
var import_node_path = require("node:path");
|
|
42
|
+
var RESET = "\x1B[0m";
|
|
43
|
+
var DIM = "\x1B[2;37m";
|
|
44
|
+
var SOFT = "\x1B[37m";
|
|
45
|
+
var GREEN = "\x1B[32m";
|
|
46
|
+
var RED = "\x1B[31m";
|
|
47
|
+
function dim(s) {
|
|
48
|
+
return `${DIM}${s}${RESET}`;
|
|
49
|
+
}
|
|
50
|
+
function renderModel(input) {
|
|
51
|
+
const raw = input?.model?.display_name;
|
|
52
|
+
if (typeof raw !== "string" || raw.length === 0)
|
|
53
|
+
return "";
|
|
54
|
+
const cleaned = raw.replace("Claude ", "").replace(/\s*\([^)]*\)\s*/g, " ").trim();
|
|
55
|
+
if (cleaned.length === 0)
|
|
56
|
+
return "";
|
|
57
|
+
const family = /Opus/i.test(cleaned) ? "Opus" : /Sonnet/i.test(cleaned) ? "Sonnet" : /Haiku/i.test(cleaned) ? "Haiku" : void 0;
|
|
58
|
+
const icon = family === "Opus" ? "\u{1F9E0}" : family === "Haiku" ? "\u{1F4B2}" : "\u26A1";
|
|
59
|
+
const version = /(\d+\.?\d*)/.exec(cleaned)?.[1];
|
|
60
|
+
if (family && version)
|
|
61
|
+
return `${SOFT}${family}${RESET} ${icon} ${dim(version)}`;
|
|
62
|
+
return `${SOFT}${family ?? cleaned}${RESET} ${icon}`;
|
|
63
|
+
}
|
|
64
|
+
function renderContext(input) {
|
|
65
|
+
const ctx = input?.context_window;
|
|
66
|
+
const usage = ctx?.current_usage;
|
|
67
|
+
if (!ctx || usage === void 0 || usage === null || typeof usage !== "object")
|
|
68
|
+
return "";
|
|
69
|
+
const window = Number(ctx.context_window_size);
|
|
70
|
+
if (!Number.isFinite(window) || window <= 0)
|
|
71
|
+
return "";
|
|
72
|
+
const fields = [usage.input_tokens, usage.cache_creation_input_tokens, usage.cache_read_input_tokens];
|
|
73
|
+
const present = fields.filter((v) => typeof v === "number" && Number.isFinite(v));
|
|
74
|
+
if (present.length === 0)
|
|
75
|
+
return "";
|
|
76
|
+
const tokens = present.reduce((a, b) => a + b, 0);
|
|
77
|
+
const pct = Math.floor(tokens * 100 / window);
|
|
78
|
+
const color = pct >= 81 ? "\x1B[1;31m" : pct >= 61 ? "\x1B[31m" : pct >= 41 ? "\x1B[33m" : pct >= 21 ? "\x1B[32m" : pct >= 11 ? "\x1B[37m" : "\x1B[2;37m";
|
|
79
|
+
return `\u{1F4BF} ${color}${pct}%${RESET}`;
|
|
80
|
+
}
|
|
81
|
+
function renderDir(input, git) {
|
|
82
|
+
const cwd = input?.workspace?.current_dir ?? input?.cwd;
|
|
83
|
+
let dir = "";
|
|
84
|
+
if (typeof cwd === "string" && cwd.length > 0) {
|
|
85
|
+
const base = (0, import_node_path.basename)(cwd);
|
|
86
|
+
if (base)
|
|
87
|
+
dir = dim(base);
|
|
88
|
+
}
|
|
89
|
+
if (git && git.branch) {
|
|
90
|
+
const star = git.dirty ? `${RED}*${RESET}` : "";
|
|
91
|
+
const suffix = `(${GREEN}${git.branch}${RESET}${star})`;
|
|
92
|
+
return dir ? `${dir} ${suffix}` : suffix;
|
|
93
|
+
}
|
|
94
|
+
return dir;
|
|
95
|
+
}
|
|
96
|
+
function renderChip(input) {
|
|
97
|
+
const sid = input?.session_id;
|
|
98
|
+
if (typeof sid !== "string" || sid.length === 0)
|
|
99
|
+
return "";
|
|
100
|
+
return `\u{1F517} ${dim(sid)}`;
|
|
101
|
+
}
|
|
102
|
+
function renderStandaloneStatusline(input, opts) {
|
|
103
|
+
const parts = [];
|
|
104
|
+
const dir = renderDir(input, opts?.git);
|
|
105
|
+
if (dir)
|
|
106
|
+
parts.push(dir);
|
|
107
|
+
const model = renderModel(input);
|
|
108
|
+
if (model)
|
|
109
|
+
parts.push(model);
|
|
110
|
+
const ctx = renderContext(input);
|
|
111
|
+
if (ctx)
|
|
112
|
+
parts.push(ctx);
|
|
113
|
+
const chip = renderChip(input);
|
|
114
|
+
if (chip)
|
|
115
|
+
parts.push(chip);
|
|
116
|
+
return parts.join(` ${DIM}\xB7${RESET} `);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// src/hooks/statusline.ts
|
|
120
|
+
function parseGitStatus(stdout) {
|
|
121
|
+
if (typeof stdout !== "string" || stdout.length === 0)
|
|
122
|
+
return void 0;
|
|
123
|
+
const lines = stdout.split("\n");
|
|
124
|
+
const header = lines.find((l) => l.startsWith("## "));
|
|
125
|
+
if (!header)
|
|
126
|
+
return void 0;
|
|
127
|
+
const rest = header.slice(3);
|
|
128
|
+
let branch;
|
|
129
|
+
if (rest.startsWith("No commits yet on ")) {
|
|
130
|
+
branch = rest.slice("No commits yet on ".length).trim();
|
|
131
|
+
} else if (rest.startsWith("Initial commit on ")) {
|
|
132
|
+
branch = rest.slice("Initial commit on ".length).trim();
|
|
133
|
+
} else if (rest.startsWith("HEAD (no branch)")) {
|
|
134
|
+
branch = void 0;
|
|
135
|
+
} else {
|
|
136
|
+
branch = rest.split(/\.\.\.| /, 1)[0].trim();
|
|
137
|
+
}
|
|
138
|
+
if (!branch)
|
|
139
|
+
return void 0;
|
|
140
|
+
const dirty = lines.some((l) => l.length > 0 && !l.startsWith("## "));
|
|
141
|
+
return { branch, dirty };
|
|
142
|
+
}
|
|
143
|
+
function readGit(cwd) {
|
|
144
|
+
try {
|
|
145
|
+
const res = (0, import_node_child_process.spawnSync)("git", ["status", "--porcelain=v1", "--branch"], {
|
|
146
|
+
cwd,
|
|
147
|
+
timeout: 400,
|
|
148
|
+
encoding: "utf8",
|
|
149
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
150
|
+
windowsHide: true
|
|
151
|
+
});
|
|
152
|
+
if (res.error || res.status !== 0 || typeof res.stdout !== "string")
|
|
153
|
+
return void 0;
|
|
154
|
+
return parseGitStatus(res.stdout);
|
|
155
|
+
} catch {
|
|
156
|
+
return void 0;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
async function runStatusline() {
|
|
160
|
+
let data = "";
|
|
161
|
+
for await (const chunk of import_node_process.default.stdin)
|
|
162
|
+
data += chunk;
|
|
163
|
+
let json;
|
|
164
|
+
try {
|
|
165
|
+
json = JSON.parse(data);
|
|
166
|
+
} catch {
|
|
167
|
+
json = {};
|
|
168
|
+
}
|
|
169
|
+
const cwd = json?.workspace?.current_dir ?? json?.cwd;
|
|
170
|
+
const git = typeof cwd === "string" && cwd.length > 0 ? readGit(cwd) : void 0;
|
|
171
|
+
import_node_process.default.stdout.write(renderStandaloneStatusline(json ?? {}, { git }));
|
|
172
|
+
import_node_process.default.exit(0);
|
|
173
|
+
}
|
|
174
|
+
if (typeof require !== "undefined" && typeof module !== "undefined" && require.main === module) {
|
|
175
|
+
void runStatusline();
|
|
176
|
+
}
|
|
177
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
178
|
+
0 && (module.exports = {
|
|
179
|
+
parseGitStatus
|
|
180
|
+
});
|