@workscribe/cli 3.0.1 → 3.1.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/dist/index.js +357 -42
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -378,7 +378,7 @@ var init_logger = __esm({
|
|
|
378
378
|
success: (msg) => console.log(import_chalk.default.green("\u2713"), msg),
|
|
379
379
|
warn: (msg) => console.log(import_chalk.default.yellow("\u26A0"), msg),
|
|
380
380
|
error: (msg) => console.error(import_chalk.default.red("\u2717"), msg),
|
|
381
|
-
/** A warning on stderr — keeps stdout clean for JSON output
|
|
381
|
+
/** A warning on stderr — keeps stdout clean for JSON and plain text output, and pipes. */
|
|
382
382
|
notice: (msg) => process.stderr.write(`${import_chalk.default.yellow("\u26A0")} ${msg}
|
|
383
383
|
`),
|
|
384
384
|
plain: (msg) => console.log(msg)
|
|
@@ -2635,6 +2635,29 @@ var init_db = __esm({
|
|
|
2635
2635
|
});
|
|
2636
2636
|
|
|
2637
2637
|
// src/capture/redact.ts
|
|
2638
|
+
function sameCommand(maxParts) {
|
|
2639
|
+
const quoted = String.raw`"[^"]{0,${MAX_QUOTED_LENGTH}}"|'[^']{0,${MAX_QUOTED_LENGTH}}'`;
|
|
2640
|
+
return String.raw`(?:(?:${quoted}|\\\n|[^|;&\n"']){0,${maxParts}}?|[^|;&\n]{0,${maxParts}}?)`;
|
|
2641
|
+
}
|
|
2642
|
+
function valueAfter(prefix, flags = "g") {
|
|
2643
|
+
return new RegExp(`(?<=${prefix})${VALUE}`, flags);
|
|
2644
|
+
}
|
|
2645
|
+
function toolFlagValue(tools, flag) {
|
|
2646
|
+
return valueAfter(String.raw`${TOOL_WORD_START}(?:${tools})${TOOL_WORD_END}${SAME_COMMAND}\s${flag}`);
|
|
2647
|
+
}
|
|
2648
|
+
function quotedValuesAfterName(prefix, name, flags = "g") {
|
|
2649
|
+
return [
|
|
2650
|
+
new RegExp(String.raw`(?<=${prefix}"${name})[^"\s][^"\n]*`, flags),
|
|
2651
|
+
new RegExp(String.raw`(?<=${prefix}'${name})[^'\s][^'\n]*`, flags)
|
|
2652
|
+
];
|
|
2653
|
+
}
|
|
2654
|
+
function valuesAfterName(prefix, name, flags = "g") {
|
|
2655
|
+
return [
|
|
2656
|
+
...quotedValuesAfterName(prefix, name, flags),
|
|
2657
|
+
new RegExp(String.raw`(?<=${prefix}${name})(?:${QUOTED})`, flags),
|
|
2658
|
+
new RegExp(String.raw`(?<=${prefix}${name})[^\s"'|;&]+`, flags)
|
|
2659
|
+
];
|
|
2660
|
+
}
|
|
2638
2661
|
function redact(command, extraPatterns = []) {
|
|
2639
2662
|
let result = command;
|
|
2640
2663
|
const allPatterns = [...BUILTIN_PATTERNS];
|
|
@@ -2646,22 +2669,73 @@ function redact(command, extraPatterns = []) {
|
|
|
2646
2669
|
}
|
|
2647
2670
|
for (const pattern of allPatterns) {
|
|
2648
2671
|
pattern.lastIndex = 0;
|
|
2649
|
-
result = result.replace(pattern,
|
|
2672
|
+
result = result.replace(pattern, REDACTED_TEXT);
|
|
2650
2673
|
}
|
|
2651
2674
|
return result;
|
|
2652
2675
|
}
|
|
2653
|
-
var BUILTIN_PATTERNS;
|
|
2676
|
+
var QUOTED, WORD_REST, VALUE, VALUE_OR_DASHED, MAX_COMMAND_PARTS, MAX_QUOTED_LENGTH, MAX_PARTS_BEFORE_LOGIN, MAX_PARTS_AFTER_LOGIN, SAME_COMMAND, NOT_PART_OF_A_WORD, NOT_A_NAME, NOT_IN_A_MESSAGE, TOOL_WORD_START, TOOL_WORD_END, NOT_A_PORT_MAPPING, LONG_SECRET_FLAGS, LONG_FLAG_VALUE_START, MAX_SORT_FIELD_DIGITS, SORT_FIELD, NOT_A_KEY, MAX_SLUG_WORD_LENGTH, MAX_SLUG_WORDS_AFTER_FIRST, SLUG_WORD, UUID_IN_A_KEY, SLUG_AFTER_SK, CONTAINER_LOGIN_TOOLS, EVERYDAY_HEADERS, DISTINCTIVE_HEADERS, HEADER_FLAG, SENSITIVE_VARIABLE_WORDS, QUERY_SECRET_NAME, JSON_SECRET_NAME, BUILTIN_PATTERNS, REDACTED_TEXT;
|
|
2654
2677
|
var init_redact = __esm({
|
|
2655
2678
|
"src/capture/redact.ts"() {
|
|
2656
2679
|
"use strict";
|
|
2680
|
+
QUOTED = String.raw`"[^"]*"|'[^']*'`;
|
|
2681
|
+
WORD_REST = String.raw`(?:[^\s"');&|]|["');&|](?=[^\s;&|)]))*`;
|
|
2682
|
+
VALUE = String.raw`(?:${QUOTED}|[^\s"'\-]${WORD_REST})`;
|
|
2683
|
+
VALUE_OR_DASHED = String.raw`(?:${QUOTED}|[^\s"']${WORD_REST})`;
|
|
2684
|
+
MAX_COMMAND_PARTS = 1e3;
|
|
2685
|
+
MAX_QUOTED_LENGTH = 64e3;
|
|
2686
|
+
MAX_PARTS_BEFORE_LOGIN = 200;
|
|
2687
|
+
MAX_PARTS_AFTER_LOGIN = 300;
|
|
2688
|
+
SAME_COMMAND = sameCommand(MAX_COMMAND_PARTS);
|
|
2689
|
+
NOT_PART_OF_A_WORD = String.raw`(?<![\w.:@-])`;
|
|
2690
|
+
NOT_A_NAME = String.raw`(?<!--name(?:\s+|=)|\bssh\s+)`;
|
|
2691
|
+
NOT_IN_A_MESSAGE = String.raw`(?<!\s(?:-[as]*m|--message|--title|--body|--subject)[\s=]*["'][^"'\n]{0,${MAX_COMMAND_PARTS}})`;
|
|
2692
|
+
TOOL_WORD_START = `${NOT_IN_A_MESSAGE}${NOT_A_NAME}${NOT_PART_OF_A_WORD}`;
|
|
2693
|
+
TOOL_WORD_END = String.raw`(?:\.exe)?["'\x60)]?(?=\s)`;
|
|
2694
|
+
NOT_A_PORT_MAPPING = String.raw`(?!(?:[\d.]+:)?\d+:\d+(?:\/\w+)?(?=\s|$))`;
|
|
2695
|
+
LONG_SECRET_FLAGS = [
|
|
2696
|
+
"password",
|
|
2697
|
+
"(?!no-)[\\w-]*-password",
|
|
2698
|
+
"passwd",
|
|
2699
|
+
"passphrase",
|
|
2700
|
+
"pass",
|
|
2701
|
+
"pwd",
|
|
2702
|
+
"secret(?:-key)?",
|
|
2703
|
+
"client[-_]secret",
|
|
2704
|
+
"token",
|
|
2705
|
+
"access-token",
|
|
2706
|
+
"refresh-token",
|
|
2707
|
+
"auth[-_]?token",
|
|
2708
|
+
"private-key",
|
|
2709
|
+
"api[-_]?key"
|
|
2710
|
+
].join("|");
|
|
2711
|
+
LONG_FLAG_VALUE_START = String.raw`(?:=|\s+(?!--))`;
|
|
2712
|
+
MAX_SORT_FIELD_DIGITS = 2;
|
|
2713
|
+
SORT_FIELD = String.raw`\d{1,${MAX_SORT_FIELD_DIGITS}}`;
|
|
2714
|
+
NOT_A_KEY = String.raw`(?:${SORT_FIELD}(?:[.,]${SORT_FIELD})*|[\w./~-]*\.(?:key|pem|crt|p12|pfx|der)|[\w./~-]*\/id_\w+)(?=\s|$)`;
|
|
2715
|
+
MAX_SLUG_WORD_LENGTH = 15;
|
|
2716
|
+
MAX_SLUG_WORDS_AFTER_FIRST = 8;
|
|
2717
|
+
SLUG_WORD = `[a-z0-9]{1,${MAX_SLUG_WORD_LENGTH}}`;
|
|
2718
|
+
UUID_IN_A_KEY = String.raw`[a-z-]{0,20}[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}`;
|
|
2719
|
+
SLUG_AFTER_SK = String.raw`(?!${UUID_IN_A_KEY})${SLUG_WORD}(?:-${SLUG_WORD}){0,${MAX_SLUG_WORDS_AFTER_FIRST}}(?![\w-])`;
|
|
2720
|
+
CONTAINER_LOGIN_TOOLS = "docker|podman|podman-remote|nerdctl|helm";
|
|
2721
|
+
EVERYDAY_HEADERS = "api-key|cookie|set-cookie";
|
|
2722
|
+
DISTINCTIVE_HEADERS = "x-api-key|x-auth-token|x-access-token";
|
|
2723
|
+
HEADER_FLAG = String.raw`(?<![\w-])(?:-\w*H|--(?:proxy-)?header)[\s=]*`;
|
|
2724
|
+
SENSITIVE_VARIABLE_WORDS = "TOKEN|SECRET|KEY|PASSWORD|PASS|AUTH|CREDENTIAL|_PWD";
|
|
2725
|
+
QUERY_SECRET_NAME = String.raw`key|[\w-]*(?:token|secret|password|passwd|pwd|api[-_]?key)`;
|
|
2726
|
+
JSON_SECRET_NAME = String.raw`[\w-]*(?:token|secret|password|passwd|pwd|api[-_]?key)`;
|
|
2657
2727
|
BUILTIN_PATTERNS = [
|
|
2658
2728
|
// AWS access keys
|
|
2659
2729
|
/AKIA[0-9A-Z]{16}/g,
|
|
2660
2730
|
// AWS secret access keys (40 char base64-ish after common env vars)
|
|
2661
|
-
|
|
2731
|
+
new RegExp(String.raw`(?<=AWS_SECRET_ACCESS_KEY[=\s]+)${VALUE_OR_DASHED}`, "gi"),
|
|
2662
2732
|
// GitHub tokens
|
|
2663
|
-
|
|
2733
|
+
/\bgh[pousr]_[a-zA-Z0-9]{36}/g,
|
|
2664
2734
|
/github_pat_[a-zA-Z0-9_]{82}/g,
|
|
2735
|
+
// AI provider, Google and npm keys
|
|
2736
|
+
new RegExp(String.raw`\bsk-(?!${SLUG_AFTER_SK})[\w-]{20,}`, "g"),
|
|
2737
|
+
/\bAIza[a-zA-Z0-9_-]{30,}/g,
|
|
2738
|
+
/\bnpm_[a-zA-Z0-9]{30,}/g,
|
|
2665
2739
|
// GitLab tokens
|
|
2666
2740
|
/glpat-[a-zA-Z0-9\-]{20}/g,
|
|
2667
2741
|
// Generic JWTs (three base64url segments)
|
|
@@ -2671,17 +2745,85 @@ var init_redact = __esm({
|
|
|
2671
2745
|
/https:\/\/hooks\.slack\.com\/services\/[A-Z0-9]+\/[A-Z0-9]+\/[a-zA-Z0-9]+/g,
|
|
2672
2746
|
// Stripe keys
|
|
2673
2747
|
/sk_(live|test)_[a-zA-Z0-9]{24,}/g,
|
|
2674
|
-
// Values after long-form secret flags
|
|
2675
|
-
|
|
2748
|
+
// Values after long-form secret flags, `--flag value` or `--flag=value`. `--password-stdin` isn't one: no match on its
|
|
2749
|
+
// `-stdin`. A bare short flag means nothing without knowing the tool: see below
|
|
2750
|
+
new RegExp(String.raw`(?<=(?<![\w-])--(?:${LONG_SECRET_FLAGS})${LONG_FLAG_VALUE_START})${VALUE_OR_DASHED}`, "gi"),
|
|
2751
|
+
new RegExp(String.raw`(?<=(?<![\w-])--key${LONG_FLAG_VALUE_START})(?!${NOT_A_KEY})${VALUE_OR_DASHED}`, "gi"),
|
|
2752
|
+
// A password attached to the flag: `mysql -pSECRET`. `mysql -p db` prompts, so there's no value to remove, and
|
|
2753
|
+
// `psql -p 5432` is a port, so psql isn't listed
|
|
2754
|
+
toolFlagValue(
|
|
2755
|
+
"mysql|mysqldump|mysqladmin|mysqlimport|mysqlshow|mysqlcheck|mariadb|mariadb-dump|mariadb-admin|mariadb-import|mariadb-show|mariadb-check",
|
|
2756
|
+
"-p"
|
|
2757
|
+
),
|
|
2758
|
+
// Short flags that take a secret, for the tools where they do
|
|
2759
|
+
toolFlagValue("sshpass", String.raw`-p\s*`),
|
|
2760
|
+
toolFlagValue("mongosh|mongo|mongodump|mongorestore|mongoexport|mongoimport", String.raw`-p\s*${NOT_A_PORT_MAPPING}`),
|
|
2761
|
+
toolFlagValue("redis-cli", String.raw`-a\s*`),
|
|
2762
|
+
toolFlagValue("ssh-keygen", String.raw`-[NP]\s*`),
|
|
2763
|
+
toolFlagValue("zip|unzip", String.raw`-P\s*`),
|
|
2764
|
+
valueAfter(
|
|
2765
|
+
String.raw`${TOOL_WORD_START}(?:${CONTAINER_LOGIN_TOOLS})${TOOL_WORD_END}[^|;&\n]{0,${MAX_PARTS_BEFORE_LOGIN}}?\slogin` + String.raw`${TOOL_WORD_END}${sameCommand(MAX_PARTS_AFTER_LOGIN)}\s-p\s*${NOT_A_PORT_MAPPING}`
|
|
2766
|
+
),
|
|
2767
|
+
// openssl's `-pass pass:SECRET`, also -passin and -passout
|
|
2768
|
+
/(?<=\s-pass(?:in|out|word)?\s+pass:)\S+/g,
|
|
2769
|
+
// curl's cookies, which also covers a cookie file's name: `curl -b s=SECRET`
|
|
2770
|
+
valueAfter(String.raw`\bcurl\b["']?${SAME_COMMAND}\s(?:--cookie|-\w*b)[\s=]+`),
|
|
2771
|
+
// The password half of `curl -u user:password`
|
|
2772
|
+
...valuesAfterName(String.raw`\bcurl\b["']?${SAME_COMMAND}\s(?:-\w*u[\s=]*|--user[\s=]+)`, String.raw`[^:\s"']*:`),
|
|
2773
|
+
// Tokens handed over on stdin: `echo SECRET | docker login --password-stdin`, `gh auth login --with-token <<< SECRET`
|
|
2774
|
+
new RegExp(
|
|
2775
|
+
String.raw`(?<=\b(?:echo(?:\s+-[neE]+)*|printf(?:\s+["']?%s(?:\\n)?["']?)?)\s+)${VALUE}` + String.raw`(?=\s*\|[^;&\n]{0,${MAX_COMMAND_PARTS}}?--(?:password-stdin|with-token))`,
|
|
2776
|
+
"g"
|
|
2777
|
+
),
|
|
2778
|
+
valueAfter(String.raw`--(?:password-stdin|with-token)\s*<<<\s*`),
|
|
2779
|
+
// Headers. A scheme or a header flag is required for Authorization, so prose like "Authorization: added middleware"
|
|
2780
|
+
// stays. An everyday word needs to look like a header, so `git commit -m "cookie: rotate on login"` stays: a header
|
|
2781
|
+
// flag, `Cookie:value` with no space, or a quoted `"Cookie: value"` outside a message
|
|
2782
|
+
/(?<=\bauthorization:\s*(?:bearer|basic|token)\s+)[^\s"']+/gi,
|
|
2783
|
+
/(?<=\bbearer\s+)(?=[A-Za-z0-9._~+/=-]*\d)[A-Za-z0-9._~+/=-]{8,}/gi,
|
|
2784
|
+
...valuesAfterName(HEADER_FLAG, String.raw`(?:${EVERYDAY_HEADERS}):\s*`, "gi"),
|
|
2785
|
+
...valuesAfterName(HEADER_FLAG, String.raw`authorization:\s*(?!(?:bearer|basic|token)\s)`, "gi"),
|
|
2786
|
+
...quotedValuesAfterName("", String.raw`${NOT_IN_A_MESSAGE}(?:${EVERYDAY_HEADERS}):\s*`, "gi"),
|
|
2787
|
+
...valuesAfterName("", String.raw`(?<![\w-])(?:${EVERYDAY_HEADERS}):`, "gi"),
|
|
2788
|
+
...valuesAfterName("", String.raw`\b(?:${DISTINCTIVE_HEADERS}):\s*`, "gi"),
|
|
2789
|
+
// Private keys, whole blocks, as heredocs and `echo` can carry them
|
|
2790
|
+
/-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g,
|
|
2791
|
+
// password=... inside a string or query: `psql "host=x password=SECRET"`, `--set db.password=SECRET`
|
|
2792
|
+
/(?<=(?:^|[\s"'?&=.])(?:password|passwd|pwd)=)[^\s"';&]+/gi,
|
|
2793
|
+
// A secret in a query string or in JSON: `curl "x.io?token=SECRET"`, `curl -d '{"password":"SECRET"}'`
|
|
2794
|
+
new RegExp(String.raw`(?<=[?&](?:${QUERY_SECRET_NAME})=)[^\s"'&#]+`, "gi"),
|
|
2795
|
+
new RegExp(String.raw`(?<=["'](?:${JSON_SECRET_NAME})\\?["']\s*:\s*\\?")[^"\\\n]+`, "gi"),
|
|
2796
|
+
// npm's auth settings, with or without `=`: `npm config set //registry/:_password SECRET`
|
|
2797
|
+
/(?<=:_(?:password|auth|authToken)[=\s]+)\S+/g,
|
|
2676
2798
|
// export VAR=VALUE where VAR looks sensitive
|
|
2677
|
-
|
|
2799
|
+
new RegExp(String.raw`(?<=export\s+(?:[A-Z_]*(?:${SENSITIVE_VARIABLE_WORDS})[A-Z_]*)=)${VALUE_OR_DASHED}`, "gi"),
|
|
2678
2800
|
// Inline assignment: VAR_WITH_SENSITIVE_KEYWORD=value cmd (e.g. API_KEY=secret npm start)
|
|
2679
2801
|
// Lookbehind matches only the variable-name= prefix, so only the value is replaced
|
|
2680
|
-
|
|
2802
|
+
new RegExp(String.raw`(?<=[A-Z_][A-Z0-9_]*(?:${SENSITIVE_VARIABLE_WORDS})[A-Z0-9_]*=)${VALUE_OR_DASHED}`, "gi"),
|
|
2803
|
+
// The same with nothing before the keyword: `TOKEN=SECRET npm start`. Capitals only, so `--author=me` and `key=value` stay
|
|
2804
|
+
new RegExp(
|
|
2805
|
+
String.raw`(?<=(?:^|[\s;&|(])(?:TOKEN|SECRET|KEY|PASSWORD|PASS|AUTH|CREDENTIALS?)=)${VALUE_OR_DASHED}`,
|
|
2806
|
+
"g"
|
|
2807
|
+
),
|
|
2681
2808
|
// Credentials embedded in connection string URLs (e.g. DATABASE_URL=postgres://user:pass@host/db)
|
|
2682
2809
|
// Matches the password segment between :// user : password @ — preserves scheme and host
|
|
2683
|
-
/(?<=[a-zA-Z][a-zA-Z0-9+.-]*:\/\/[^:@\s/]
|
|
2810
|
+
/(?<=[a-zA-Z][a-zA-Z0-9+.-]*:\/\/[^:@\s/]*:)[^@\s]+(?=@)/g,
|
|
2811
|
+
// A token as the whole userinfo of an https URL: `git clone https://TOKEN@github.com/org/repo`
|
|
2812
|
+
/(?<=https?:\/\/)[^\s:@/?#]+(?=@)/g
|
|
2684
2813
|
];
|
|
2814
|
+
REDACTED_TEXT = "[REDACTED]";
|
|
2815
|
+
}
|
|
2816
|
+
});
|
|
2817
|
+
|
|
2818
|
+
// src/capture/hint.ts
|
|
2819
|
+
function commandHint(safeCommand) {
|
|
2820
|
+
return safeCommand.trim().slice(0, HINT_LENGTH);
|
|
2821
|
+
}
|
|
2822
|
+
var HINT_LENGTH;
|
|
2823
|
+
var init_hint = __esm({
|
|
2824
|
+
"src/capture/hint.ts"() {
|
|
2825
|
+
"use strict";
|
|
2826
|
+
HINT_LENGTH = 120;
|
|
2685
2827
|
}
|
|
2686
2828
|
});
|
|
2687
2829
|
|
|
@@ -2853,13 +2995,13 @@ var init_git_snapshot = __esm({
|
|
|
2853
2995
|
});
|
|
2854
2996
|
|
|
2855
2997
|
// src/capture/aider.ts
|
|
2856
|
-
function readLastAiderPrompt(cwd) {
|
|
2998
|
+
function readLastAiderPrompt(cwd, extraRedactions = []) {
|
|
2857
2999
|
try {
|
|
2858
3000
|
const histPath = import_path8.default.join(cwd, HISTORY_FILE);
|
|
2859
3001
|
const content = import_fs10.default.readFileSync(histPath, "utf-8");
|
|
2860
3002
|
const matches = [...content.matchAll(/^#### (.+)$/gm)];
|
|
2861
3003
|
if (!matches.length) return null;
|
|
2862
|
-
return matches[matches.length - 1][1].trim().slice(0, PROMPT_MAX_LENGTH);
|
|
3004
|
+
return redact(matches[matches.length - 1][1].trim(), extraRedactions).slice(0, PROMPT_MAX_LENGTH);
|
|
2863
3005
|
} catch {
|
|
2864
3006
|
return null;
|
|
2865
3007
|
}
|
|
@@ -2870,6 +3012,7 @@ var init_aider = __esm({
|
|
|
2870
3012
|
"use strict";
|
|
2871
3013
|
import_fs10 = __toESM(require("fs"));
|
|
2872
3014
|
import_path8 = __toESM(require("path"));
|
|
3015
|
+
init_redact();
|
|
2873
3016
|
HISTORY_FILE = ".aider.chat.history.md";
|
|
2874
3017
|
PROMPT_MAX_LENGTH = 200;
|
|
2875
3018
|
}
|
|
@@ -3115,7 +3258,7 @@ function captureCommand(opts) {
|
|
|
3115
3258
|
if (Date.now() - lastTime < TASK_RUN_DEDUP_WINDOW_MS) return;
|
|
3116
3259
|
}
|
|
3117
3260
|
}
|
|
3118
|
-
const command2 = opts.command
|
|
3261
|
+
const command2 = opts.command === void 0 ? opts.file ?? opts.type : redact(opts.command, config.redact.extra);
|
|
3119
3262
|
const context2 = getRepoContext(cwd, config);
|
|
3120
3263
|
const { repoName: repoName2, branch: branch2 } = context2;
|
|
3121
3264
|
const ideEvent = {
|
|
@@ -3149,17 +3292,17 @@ function captureCommand(opts) {
|
|
|
3149
3292
|
if (category === "other") {
|
|
3150
3293
|
const firstToken = safeCommand.trim().split(/\s+/)[0];
|
|
3151
3294
|
if (firstToken) metadata.tool = firstToken;
|
|
3152
|
-
metadata.hint = safeCommand
|
|
3295
|
+
metadata.hint = commandHint(safeCommand);
|
|
3153
3296
|
}
|
|
3154
3297
|
if (category === "ai_session") {
|
|
3155
3298
|
if (opts.gitBefore) {
|
|
3156
3299
|
const commits = getCommitsSince(opts.gitBefore, workDirectory);
|
|
3157
|
-
if (commits.length > 0) metadata.commits = commits;
|
|
3300
|
+
if (commits.length > 0) metadata.commits = commits.map((subject) => redact(subject, config.redact.extra));
|
|
3158
3301
|
}
|
|
3159
3302
|
if (config.capture.includeAiderPrompt !== false) {
|
|
3160
3303
|
const toolEntry = loadAIToolRegistry().find((entry) => entry.tool === metadata.tool);
|
|
3161
3304
|
if (toolEntry?.contextSource === "history-file") {
|
|
3162
|
-
const prompt = readLastAiderPrompt(cwd);
|
|
3305
|
+
const prompt = readLastAiderPrompt(cwd, config.redact.extra);
|
|
3163
3306
|
if (prompt) metadata.prompt = prompt;
|
|
3164
3307
|
}
|
|
3165
3308
|
}
|
|
@@ -3192,6 +3335,7 @@ var init_capture = __esm({
|
|
|
3192
3335
|
import_fs14 = __toESM(require("fs"));
|
|
3193
3336
|
init_db();
|
|
3194
3337
|
init_redact();
|
|
3338
|
+
init_hint();
|
|
3195
3339
|
init_git();
|
|
3196
3340
|
init_git_snapshot();
|
|
3197
3341
|
init_aider();
|
|
@@ -4373,10 +4517,10 @@ function installIntoFolder(options) {
|
|
|
4373
4517
|
const outcome = installSkill({
|
|
4374
4518
|
sourceDir: options.sourceDir,
|
|
4375
4519
|
skillsFolder: target.skillsFolder,
|
|
4376
|
-
version: "3.0
|
|
4520
|
+
version: "3.1.0",
|
|
4377
4521
|
force: options.force
|
|
4378
4522
|
});
|
|
4379
|
-
return describeInstallOutcome({ ...target, outcome, version: "3.0
|
|
4523
|
+
return describeInstallOutcome({ ...target, outcome, version: "3.1.0" });
|
|
4380
4524
|
} catch (error) {
|
|
4381
4525
|
return describeInstallFailure({ ...target, error });
|
|
4382
4526
|
}
|
|
@@ -4395,8 +4539,8 @@ function removeSkills(agents, options) {
|
|
|
4395
4539
|
}
|
|
4396
4540
|
function formatAgentSkillLine(agent, homeDir = import_os6.default.homedir()) {
|
|
4397
4541
|
const location = displayPath(import_path19.default.join(homeDir, agent.skillsFolder, SKILL_NAME), homeDir);
|
|
4398
|
-
const installState = readInstallState(import_path19.default.join(homeDir, agent.skillsFolder), "3.0
|
|
4399
|
-
const status = describeSkillStatus(installState, "3.0
|
|
4542
|
+
const installState = readInstallState(import_path19.default.join(homeDir, agent.skillsFolder), "3.1.0");
|
|
4543
|
+
const status = describeSkillStatus(installState, "3.1.0");
|
|
4400
4544
|
return `${agent.name.padEnd(AGENT_NAME_COLUMN_WIDTH)} ${STATUS_COLOURS[status.level](status.text)} ${import_chalk2.default.dim(location)}`;
|
|
4401
4545
|
}
|
|
4402
4546
|
function formatUndetectedAgentLine(agent) {
|
|
@@ -4688,10 +4832,10 @@ async function runAIToolsStep() {
|
|
|
4688
4832
|
}
|
|
4689
4833
|
async function offerSkillInstall(group, sourceDir) {
|
|
4690
4834
|
const target = describeTarget(group);
|
|
4691
|
-
const state = readInstallState(target.skillsFolder, "3.0
|
|
4835
|
+
const state = readInstallState(target.skillsFolder, "3.1.0");
|
|
4692
4836
|
const knownOutcome = outcomeWithoutPrompt(state);
|
|
4693
4837
|
if (knownOutcome) {
|
|
4694
|
-
printMessage(describeInstallOutcome({ ...target, outcome: knownOutcome, version: "3.0
|
|
4838
|
+
printMessage(describeInstallOutcome({ ...target, outcome: knownOutcome, version: "3.1.0" }));
|
|
4695
4839
|
return;
|
|
4696
4840
|
}
|
|
4697
4841
|
const { installSkill: shouldInstall } = await (0, import_prompts2.default)({
|
|
@@ -5668,6 +5812,117 @@ var init_ticket_refs = __esm({
|
|
|
5668
5812
|
}
|
|
5669
5813
|
});
|
|
5670
5814
|
|
|
5815
|
+
// src/db/jobs/scrub-secrets.ts
|
|
5816
|
+
function scrubValue(value, command) {
|
|
5817
|
+
if (command.after.includes(value)) return value;
|
|
5818
|
+
const redacted = redact(value);
|
|
5819
|
+
if (redacted !== value) return redacted;
|
|
5820
|
+
return command.before.includes(value) ? REDACTED_TEXT : value;
|
|
5821
|
+
}
|
|
5822
|
+
function scrubStrings(value, command) {
|
|
5823
|
+
if (typeof value === "string") return scrubValue(value, command);
|
|
5824
|
+
if (Array.isArray(value)) return value.map((item) => scrubStrings(item, command));
|
|
5825
|
+
if (value === null || typeof value !== "object") return value;
|
|
5826
|
+
return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, scrubStrings(item, command)]));
|
|
5827
|
+
}
|
|
5828
|
+
function hasHint(value) {
|
|
5829
|
+
return typeof value?.hint === "string";
|
|
5830
|
+
}
|
|
5831
|
+
function scrubMetadata(metadata, command) {
|
|
5832
|
+
if (metadata === null) return null;
|
|
5833
|
+
let parsed;
|
|
5834
|
+
try {
|
|
5835
|
+
parsed = JSON.parse(metadata);
|
|
5836
|
+
} catch {
|
|
5837
|
+
return redact(metadata);
|
|
5838
|
+
}
|
|
5839
|
+
const scrubbed = scrubStrings(parsed, command);
|
|
5840
|
+
if (command.after !== command.before && hasHint(scrubbed)) scrubbed.hint = commandHint(command.after);
|
|
5841
|
+
const rewritten = JSON.stringify(scrubbed);
|
|
5842
|
+
return rewritten === JSON.stringify(parsed) ? metadata : rewritten;
|
|
5843
|
+
}
|
|
5844
|
+
function scrubEvent({ command, metadata }) {
|
|
5845
|
+
const scrubbedCommand = redact(command);
|
|
5846
|
+
const scrubbedMetadata = scrubMetadata(metadata, { before: command, after: scrubbedCommand });
|
|
5847
|
+
if (scrubbedCommand === command && scrubbedMetadata === metadata) return null;
|
|
5848
|
+
return { command: scrubbedCommand, metadata: scrubbedMetadata };
|
|
5849
|
+
}
|
|
5850
|
+
function readEvents(db, afterId, limit) {
|
|
5851
|
+
return db.prepare(
|
|
5852
|
+
`SELECT id, command, metadata FROM events
|
|
5853
|
+
WHERE id > ? AND command IS NOT file_path
|
|
5854
|
+
ORDER BY id LIMIT ?`
|
|
5855
|
+
).all(afterId, limit);
|
|
5856
|
+
}
|
|
5857
|
+
function runBatch5(db, afterId, limit) {
|
|
5858
|
+
const events = readEvents(db, afterId, limit);
|
|
5859
|
+
if (events.length === 0) return { lastId: null, issues: [] };
|
|
5860
|
+
const update = db.prepare("UPDATE events SET command = ?, metadata = ? WHERE id = ?");
|
|
5861
|
+
for (const event of events) {
|
|
5862
|
+
const scrubbed = scrubEvent(event);
|
|
5863
|
+
if (scrubbed) update.run(scrubbed.command, scrubbed.metadata, event.id);
|
|
5864
|
+
}
|
|
5865
|
+
return { lastId: events[events.length - 1].id, issues: [] };
|
|
5866
|
+
}
|
|
5867
|
+
function verify4(db) {
|
|
5868
|
+
let checked = 0;
|
|
5869
|
+
let unresolved = 0;
|
|
5870
|
+
let afterId = 0;
|
|
5871
|
+
for (; ; ) {
|
|
5872
|
+
const events = readEvents(db, afterId, VERIFY_PAGE_SIZE);
|
|
5873
|
+
if (events.length === 0) break;
|
|
5874
|
+
checked += events.length;
|
|
5875
|
+
unresolved += events.filter((event) => scrubEvent(event) !== null).length;
|
|
5876
|
+
afterId = events[events.length - 1].id;
|
|
5877
|
+
}
|
|
5878
|
+
const notes = unresolved > 0 ? [`events that would still change: ${unresolved}`] : [];
|
|
5879
|
+
return { checked, resolved: checked - unresolved, unresolved, hasPassed: true, notes };
|
|
5880
|
+
}
|
|
5881
|
+
function cleanUpFile(db) {
|
|
5882
|
+
db.exec(`PRAGMA busy_timeout = ${CLEANUP_LOCK_WAIT_MS}`);
|
|
5883
|
+
try {
|
|
5884
|
+
if (getMetaValue(db, CLEANUP_KEY) === CLEANUP_NEEDS_VACUUM) {
|
|
5885
|
+
db.exec("VACUUM");
|
|
5886
|
+
setMetaValue(db, CLEANUP_KEY, CLEANUP_NEEDS_CHECKPOINT);
|
|
5887
|
+
}
|
|
5888
|
+
const result = db.prepare("PRAGMA wal_checkpoint(TRUNCATE)").get();
|
|
5889
|
+
if (result?.busy) {
|
|
5890
|
+
debugLog(`data job ${JOB_NAME}: file cleanup`, "left for later, a reader is busy");
|
|
5891
|
+
return;
|
|
5892
|
+
}
|
|
5893
|
+
deleteMetaValue(db, CLEANUP_KEY);
|
|
5894
|
+
} finally {
|
|
5895
|
+
db.exec(`PRAGMA busy_timeout = ${BUSY_TIMEOUT_MS}`);
|
|
5896
|
+
}
|
|
5897
|
+
}
|
|
5898
|
+
var JOB_NAME, VERIFY_PAGE_SIZE, CLEANUP_KEY, CLEANUP_NEEDS_VACUUM, CLEANUP_NEEDS_CHECKPOINT, CLEANUP_LOCK_WAIT_MS, scrubSecretsJob;
|
|
5899
|
+
var init_scrub_secrets = __esm({
|
|
5900
|
+
"src/db/jobs/scrub-secrets.ts"() {
|
|
5901
|
+
"use strict";
|
|
5902
|
+
init_transaction();
|
|
5903
|
+
init_store2();
|
|
5904
|
+
init_hint();
|
|
5905
|
+
init_redact();
|
|
5906
|
+
init_logger();
|
|
5907
|
+
JOB_NAME = "scrub-secrets";
|
|
5908
|
+
VERIFY_PAGE_SIZE = 500;
|
|
5909
|
+
CLEANUP_KEY = "scrub-secrets:file-cleanup";
|
|
5910
|
+
CLEANUP_NEEDS_VACUUM = "vacuum";
|
|
5911
|
+
CLEANUP_NEEDS_CHECKPOINT = "checkpoint";
|
|
5912
|
+
CLEANUP_LOCK_WAIT_MS = 200;
|
|
5913
|
+
scrubSecretsJob = {
|
|
5914
|
+
name: JOB_NAME,
|
|
5915
|
+
version: 1,
|
|
5916
|
+
description: "Remove secrets from stored commands and metadata",
|
|
5917
|
+
// Redacting what's already redacted changes nothing, so a rerun only needs the file cleaned again
|
|
5918
|
+
prepare: (db) => setMetaValue(db, CLEANUP_KEY, CLEANUP_NEEDS_VACUUM),
|
|
5919
|
+
runBatch: runBatch5,
|
|
5920
|
+
verify: verify4,
|
|
5921
|
+
cleanup: { isPending: (db) => getMetaValue(db, CLEANUP_KEY) !== null, run: cleanUpFile }
|
|
5922
|
+
};
|
|
5923
|
+
}
|
|
5924
|
+
});
|
|
5925
|
+
|
|
5671
5926
|
// src/db/jobs/index.ts
|
|
5672
5927
|
var JOBS;
|
|
5673
5928
|
var init_jobs = __esm({
|
|
@@ -5678,10 +5933,12 @@ var init_jobs = __esm({
|
|
|
5678
5933
|
init_summary_anchors();
|
|
5679
5934
|
init_drop_old_sessions();
|
|
5680
5935
|
init_ticket_refs();
|
|
5936
|
+
init_scrub_secrets();
|
|
5681
5937
|
JOBS = [
|
|
5682
5938
|
createProjectDimensionsJob({ probeDirectory }),
|
|
5683
5939
|
summaryAnchorsJob,
|
|
5684
5940
|
ticketRefsJob,
|
|
5941
|
+
scrubSecretsJob,
|
|
5685
5942
|
dropOldSessionsJob
|
|
5686
5943
|
];
|
|
5687
5944
|
}
|
|
@@ -5846,9 +6103,22 @@ function recordFailure(db, job, message) {
|
|
|
5846
6103
|
debugLog(`data job ${job.name}: couldn't record the failure`, error);
|
|
5847
6104
|
}
|
|
5848
6105
|
}
|
|
6106
|
+
function runPendingCleanups(db, jobs) {
|
|
6107
|
+
for (const job of jobs) {
|
|
6108
|
+
if (!job.cleanup || !isJobDone(getJobRow(db, job.name), job)) continue;
|
|
6109
|
+
try {
|
|
6110
|
+
if (job.cleanup.isPending(db)) job.cleanup.run(db);
|
|
6111
|
+
} catch (error) {
|
|
6112
|
+
debugLog(`data job ${job.name}: cleanup`, error);
|
|
6113
|
+
}
|
|
6114
|
+
}
|
|
6115
|
+
}
|
|
5849
6116
|
function runPendingJobs(db, jobs, options) {
|
|
5850
6117
|
const pending = jobs.filter((job) => !isJobDone(getJobRow(db, job.name), job));
|
|
5851
|
-
if (pending.length === 0)
|
|
6118
|
+
if (pending.length === 0) {
|
|
6119
|
+
runPendingCleanups(db, jobs);
|
|
6120
|
+
return { backup: "not-needed", jobs: [] };
|
|
6121
|
+
}
|
|
5852
6122
|
const backup = options.ensureBackup();
|
|
5853
6123
|
if (backup !== "ready") return { backup, jobs: [] };
|
|
5854
6124
|
const now = options.now ?? (() => /* @__PURE__ */ new Date());
|
|
@@ -5865,6 +6135,7 @@ function runPendingJobs(db, jobs, options) {
|
|
|
5865
6135
|
results.push(result);
|
|
5866
6136
|
if (result.outcome !== "done") break;
|
|
5867
6137
|
}
|
|
6138
|
+
runPendingCleanups(db, jobs);
|
|
5868
6139
|
return { backup: "ready", jobs: results };
|
|
5869
6140
|
}
|
|
5870
6141
|
var DEFAULT_BATCH_SIZE, BATCH_LOCK_WAIT_MS, NEWER_VERSION_ERROR, SupersededError;
|
|
@@ -8120,6 +8391,28 @@ var init_day = __esm({
|
|
|
8120
8391
|
}
|
|
8121
8392
|
});
|
|
8122
8393
|
|
|
8394
|
+
// src/summary/output-format.ts
|
|
8395
|
+
function keepsStdoutClean(format) {
|
|
8396
|
+
return format === "json" || format === "text";
|
|
8397
|
+
}
|
|
8398
|
+
var SUMMARY_FORMATS;
|
|
8399
|
+
var init_output_format = __esm({
|
|
8400
|
+
"src/summary/output-format.ts"() {
|
|
8401
|
+
"use strict";
|
|
8402
|
+
SUMMARY_FORMATS = ["markdown", "json", "text"];
|
|
8403
|
+
}
|
|
8404
|
+
});
|
|
8405
|
+
|
|
8406
|
+
// src/summary/plain-text.ts
|
|
8407
|
+
function toPlainText(markdown) {
|
|
8408
|
+
return markdown.replace(/^#{1,6} +/gm, "").replace(/^([ \t]*)[*•] +/gm, "$1- ").replace(/\*\*([^*\n]+)\*\*/g, "$1").replace(/`([^`\n]+)`/g, "$1").replace(/\[([^\]\n]+)\]\(([^)\s]+)\)/g, "$1 ($2)").trim();
|
|
8409
|
+
}
|
|
8410
|
+
var init_plain_text = __esm({
|
|
8411
|
+
"src/summary/plain-text.ts"() {
|
|
8412
|
+
"use strict";
|
|
8413
|
+
}
|
|
8414
|
+
});
|
|
8415
|
+
|
|
8123
8416
|
// src/cli/day-notes.ts
|
|
8124
8417
|
function printExcludedFooter(sessionPayloads, excluded) {
|
|
8125
8418
|
const excludedCounts = countExcludedEvents(sessionPayloads, excluded);
|
|
@@ -8195,10 +8488,11 @@ async function runWeeklySummary({ options, config, provider, loadDay }) {
|
|
|
8195
8488
|
}
|
|
8196
8489
|
const payload = { weekStart, weekEnd: today, by: options.by ?? "project", days };
|
|
8197
8490
|
const summary = await writeWeeklySummary(provider, payload);
|
|
8198
|
-
const
|
|
8199
|
-
if (
|
|
8491
|
+
const format = options.format ?? config.summary?.format;
|
|
8492
|
+
if (format === "json") log.plain(weekJson(payload, config.summary?.includeCategories ?? []));
|
|
8493
|
+
else if (format === "text") log.plain(toPlainText(summary));
|
|
8200
8494
|
else printSummary(summary);
|
|
8201
|
-
await postSummary({ options, config, summary, statusToStderr:
|
|
8495
|
+
await postSummary({ options, config, summary, statusToStderr: keepsStdoutClean(format) });
|
|
8202
8496
|
}
|
|
8203
8497
|
var WEEK_GIT_BUDGET_MS;
|
|
8204
8498
|
var init_weekly = __esm({
|
|
@@ -8209,6 +8503,8 @@ var init_weekly = __esm({
|
|
|
8209
8503
|
init_payload();
|
|
8210
8504
|
init_webhook2();
|
|
8211
8505
|
init_day_commits();
|
|
8506
|
+
init_output_format();
|
|
8507
|
+
init_plain_text();
|
|
8212
8508
|
init_week();
|
|
8213
8509
|
WEEK_GIT_BUDGET_MS = DAY_GIT_BUDGET_MS;
|
|
8214
8510
|
}
|
|
@@ -8224,14 +8520,24 @@ function parseWeekLayout(value) {
|
|
|
8224
8520
|
if (!layout) fail("--by must be project or day");
|
|
8225
8521
|
return layout;
|
|
8226
8522
|
}
|
|
8523
|
+
function addSummaryFormatOption(command) {
|
|
8524
|
+
return command.option("--format <format>", "print as markdown, json or text, overriding summary.format");
|
|
8525
|
+
}
|
|
8526
|
+
function parseSummaryFormat(value) {
|
|
8527
|
+
if (value === void 0) return void 0;
|
|
8528
|
+
const format = SUMMARY_FORMATS.find((candidate) => candidate === value);
|
|
8529
|
+
if (!format) fail("--format must be markdown, json or text");
|
|
8530
|
+
return format;
|
|
8531
|
+
}
|
|
8227
8532
|
async function runWeekCommand(options) {
|
|
8228
8533
|
const by = parseWeekLayout(options.by);
|
|
8534
|
+
const format = parseSummaryFormat(options.format);
|
|
8229
8535
|
const config = readConfig();
|
|
8230
8536
|
printLegacyAiNotice(config);
|
|
8231
8537
|
requireThreadData();
|
|
8232
8538
|
try {
|
|
8233
8539
|
await runWeeklySummary({
|
|
8234
|
-
options: { ...options, by },
|
|
8540
|
+
options: { ...options, by, format },
|
|
8235
8541
|
config,
|
|
8236
8542
|
provider: createSummaryWriter(config),
|
|
8237
8543
|
loadDay: loadDayThreads
|
|
@@ -8242,13 +8548,14 @@ async function runWeekCommand(options) {
|
|
|
8242
8548
|
}
|
|
8243
8549
|
function registerWeek(program) {
|
|
8244
8550
|
const weekCommand = program.command("week").description("Summarize the current week (Mon\u2013today) \u2014 the same as summary --week").option("--fresh", "accepted for 1.x scripts \u2014 the week is always rendered fresh").option("--slack", "post to Slack webhook from config").option("--webhook <url>", "post to a custom webhook URL");
|
|
8245
|
-
addWeekLayoutOption(weekCommand).action(runWeekCommand);
|
|
8551
|
+
addSummaryFormatOption(addWeekLayoutOption(weekCommand)).action(runWeekCommand);
|
|
8246
8552
|
}
|
|
8247
8553
|
var WEEK_LAYOUTS;
|
|
8248
8554
|
var init_week2 = __esm({
|
|
8249
8555
|
"src/cli/week.ts"() {
|
|
8250
8556
|
"use strict";
|
|
8251
8557
|
init_config();
|
|
8558
|
+
init_output_format();
|
|
8252
8559
|
init_weekly();
|
|
8253
8560
|
init_writer();
|
|
8254
8561
|
init_notices();
|
|
@@ -8293,8 +8600,9 @@ function printCapturedEvents(sessionPayloads, excluded) {
|
|
|
8293
8600
|
}
|
|
8294
8601
|
function registerSummary(program) {
|
|
8295
8602
|
const summaryCommand = program.command("summary").description("Generate a work summary").option("--date <YYYY-MM-DD>", "date to summarize (default: today)").option("--week", "summarize the current week").option("--fresh", "ignore saved summaries and render the template").option("--verbose", "show all captured events, including those left out of the summary").option("--slack", "post summary to Slack webhook from config").option("--webhook <url>", "post summary to a custom webhook URL");
|
|
8296
|
-
addWeekLayoutOption(summaryCommand).action(async (options) => {
|
|
8603
|
+
addSummaryFormatOption(addWeekLayoutOption(summaryCommand)).action(async (options) => {
|
|
8297
8604
|
if (options.by !== void 0 && !options.week) fail("--by only applies to --week");
|
|
8605
|
+
const formatOption = parseSummaryFormat(options.format);
|
|
8298
8606
|
if (options.week) {
|
|
8299
8607
|
await runWeekCommand(options);
|
|
8300
8608
|
return;
|
|
@@ -8317,7 +8625,8 @@ function registerSummary(program) {
|
|
|
8317
8625
|
log.plain(`No activity captured for ${date}`);
|
|
8318
8626
|
return;
|
|
8319
8627
|
}
|
|
8320
|
-
const
|
|
8628
|
+
const format = formatOption ?? config.summary?.format;
|
|
8629
|
+
const keepsStdoutToOutput = keepsStdoutClean(format);
|
|
8321
8630
|
let day;
|
|
8322
8631
|
try {
|
|
8323
8632
|
day = await renderDay({ date, blocks, config, provider, fresh: options.fresh });
|
|
@@ -8328,11 +8637,13 @@ function registerSummary(program) {
|
|
|
8328
8637
|
const { sessionPayloads, saved, fullSummary, needsGeneration } = day;
|
|
8329
8638
|
const excluded = buildExcludedSet(config.summary?.includeCategories ?? []);
|
|
8330
8639
|
if (needsGeneration && options.verbose) {
|
|
8331
|
-
if (
|
|
8640
|
+
if (keepsStdoutToOutput) log.notice(`--verbose is skipped with the ${format} format, to keep the output clean`);
|
|
8332
8641
|
else printCapturedEvents(sessionPayloads, excluded);
|
|
8333
8642
|
}
|
|
8334
|
-
if (
|
|
8643
|
+
if (format === "json") {
|
|
8335
8644
|
log.plain(toJsonOutput(day, date));
|
|
8645
|
+
} else if (format === "text") {
|
|
8646
|
+
log.plain(toPlainText(fullSummary));
|
|
8336
8647
|
} else {
|
|
8337
8648
|
log.plain("");
|
|
8338
8649
|
log.plain(fullSummary);
|
|
@@ -8340,7 +8651,7 @@ function registerSummary(program) {
|
|
|
8340
8651
|
printSavedNote(saved);
|
|
8341
8652
|
if (needsGeneration) printExcludedFooter(sessionPayloads, excluded);
|
|
8342
8653
|
}
|
|
8343
|
-
await postSummary({ options, config, summary: fullSummary, statusToStderr:
|
|
8654
|
+
await postSummary({ options, config, summary: fullSummary, statusToStderr: keepsStdoutToOutput });
|
|
8344
8655
|
});
|
|
8345
8656
|
}
|
|
8346
8657
|
var import_chalk8;
|
|
@@ -8357,6 +8668,8 @@ var init_summary = __esm({
|
|
|
8357
8668
|
init_notices();
|
|
8358
8669
|
init_webhook2();
|
|
8359
8670
|
init_day();
|
|
8671
|
+
init_output_format();
|
|
8672
|
+
init_plain_text();
|
|
8360
8673
|
init_day_notes();
|
|
8361
8674
|
init_thread_day();
|
|
8362
8675
|
init_week2();
|
|
@@ -8980,7 +9293,8 @@ var init_profile = __esm({
|
|
|
8980
9293
|
function registerNote(program) {
|
|
8981
9294
|
program.command("note <text>").description("Attach a free-text annotation to the current session").action((text) => {
|
|
8982
9295
|
const directory = currentDirectory();
|
|
8983
|
-
const
|
|
9296
|
+
const config = readConfig();
|
|
9297
|
+
const context = getRepoContext(directory, config);
|
|
8984
9298
|
const { repoName, branch } = context;
|
|
8985
9299
|
insertEvent({
|
|
8986
9300
|
captured_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -8991,7 +9305,7 @@ function registerNote(program) {
|
|
|
8991
9305
|
repo_name: repoName,
|
|
8992
9306
|
branch,
|
|
8993
9307
|
category: "note",
|
|
8994
|
-
metadata: JSON.stringify({ text }),
|
|
9308
|
+
metadata: JSON.stringify({ text: redact(text, config.redact.extra) }),
|
|
8995
9309
|
source: null,
|
|
8996
9310
|
file_path: null,
|
|
8997
9311
|
dimensions: eventDimensions(context)
|
|
@@ -9005,6 +9319,7 @@ var init_note = __esm({
|
|
|
9005
9319
|
init_db();
|
|
9006
9320
|
init_git();
|
|
9007
9321
|
init_dimensions3();
|
|
9322
|
+
init_redact();
|
|
9008
9323
|
init_config();
|
|
9009
9324
|
init_working_directory();
|
|
9010
9325
|
init_logger();
|
|
@@ -9034,7 +9349,7 @@ function registerBugReport(program) {
|
|
|
9034
9349
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
9035
9350
|
const reportPath = import_path30.default.join(WORKSCRIBE_DIR, `bug-report-${timestamp}.txt`);
|
|
9036
9351
|
const systemInfo = [
|
|
9037
|
-
`Workscribe version : ${"3.0
|
|
9352
|
+
`Workscribe version : ${"3.1.0"}`,
|
|
9038
9353
|
`Node.js version : ${process.version}`,
|
|
9039
9354
|
`Platform : ${process.platform}`,
|
|
9040
9355
|
`Architecture : ${process.arch}`,
|
|
@@ -9065,7 +9380,7 @@ function registerBugReport(program) {
|
|
|
9065
9380
|
process.exit(1);
|
|
9066
9381
|
}
|
|
9067
9382
|
const params = new URLSearchParams({
|
|
9068
|
-
title: `Bug report \u2014 workscribe ${"3.0
|
|
9383
|
+
title: `Bug report \u2014 workscribe ${"3.1.0"}`,
|
|
9069
9384
|
body: `<!-- Attach ${import_path30.default.basename(reportPath)} or paste the relevant sections below -->
|
|
9070
9385
|
|
|
9071
9386
|
**Describe the issue:**
|
|
@@ -9156,7 +9471,7 @@ function reportRun(result) {
|
|
|
9156
9471
|
function registerUpgrade(program) {
|
|
9157
9472
|
program.command("upgrade").description("Bring your stored data up to date after updating Workscribe (backs it up first)").action(() => {
|
|
9158
9473
|
const announced = /* @__PURE__ */ new Set();
|
|
9159
|
-
const result = runDataJobs("3.0
|
|
9474
|
+
const result = runDataJobs("3.1.0", {
|
|
9160
9475
|
onProgress: ({ job }) => {
|
|
9161
9476
|
if (announced.has(job.name)) return;
|
|
9162
9477
|
announced.add(job.name);
|
|
@@ -9646,7 +9961,7 @@ function isNewer(latest, current) {
|
|
|
9646
9961
|
return latestPatch > currentPatch;
|
|
9647
9962
|
}
|
|
9648
9963
|
function checkForUpdate() {
|
|
9649
|
-
const current = "3.0
|
|
9964
|
+
const current = "3.1.0";
|
|
9650
9965
|
const cache = readCache();
|
|
9651
9966
|
if (cache && isNewer(cache.latestVersion, current)) {
|
|
9652
9967
|
process.stderr.write(
|
|
@@ -9669,7 +9984,7 @@ function checkForUpdate() {
|
|
|
9669
9984
|
function buildTelemetryPayload(config) {
|
|
9670
9985
|
return {
|
|
9671
9986
|
installId: config.telemetry.installId,
|
|
9672
|
-
cliVersion: "3.0
|
|
9987
|
+
cliVersion: "3.1.0",
|
|
9673
9988
|
platform: import_os12.default.platform(),
|
|
9674
9989
|
nodeVersion: process.version
|
|
9675
9990
|
};
|
|
@@ -9747,10 +10062,10 @@ var require_main = __commonJS({
|
|
|
9747
10062
|
pingTelemetry();
|
|
9748
10063
|
}
|
|
9749
10064
|
if (shouldRunDataJobs(process.argv.slice(2))) {
|
|
9750
|
-
runDataJobsBeforeCommand(invokedCommand, "3.0
|
|
10065
|
+
runDataJobsBeforeCommand(invokedCommand, "3.1.0");
|
|
9751
10066
|
}
|
|
9752
10067
|
var program = new import_commander.Command();
|
|
9753
|
-
program.name("workscribe").description("Automatic developer work journal").version("3.0
|
|
10068
|
+
program.name("workscribe").description("Automatic developer work journal").version("3.1.0");
|
|
9754
10069
|
registerCapture(program);
|
|
9755
10070
|
registerHook(program);
|
|
9756
10071
|
registerInit(program);
|