codex-token-saver 1.0.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.
@@ -0,0 +1,163 @@
1
+ const path = require("node:path");
2
+ const vscode = require("vscode");
3
+
4
+ let corePromise;
5
+
6
+ function loadCore() {
7
+ if (!corePromise) corePromise = import("../core.js");
8
+ return corePromise;
9
+ }
10
+
11
+ function workspaceRoot() {
12
+ return vscode.workspace.workspaceFolders?.[0]?.uri.fsPath;
13
+ }
14
+
15
+ function requireWorkspace() {
16
+ const root = workspaceRoot();
17
+ if (!root) {
18
+ vscode.window.showWarningMessage("Codex Context: open a workspace folder first.");
19
+ throw new Error("Open a workspace folder first.");
20
+ }
21
+ return root;
22
+ }
23
+
24
+ function maxFileSizeKb() {
25
+ return vscode.workspace.getConfiguration("codexContext").get("maxFileSizeKb", 300);
26
+ }
27
+
28
+ async function handleCommand(output, action) {
29
+ try {
30
+ const core = await loadCore();
31
+ const logger = core.createLogger({
32
+ root: workspaceRoot() ?? process.cwd(),
33
+ sink: {
34
+ log: (message) => output.appendLine(message),
35
+ warn: (message) => output.appendLine(message),
36
+ error: (message) => output.appendLine(message)
37
+ }
38
+ });
39
+ await action(core, logger);
40
+ } catch (error) {
41
+ output.appendLine(error instanceof Error ? error.message : String(error));
42
+ vscode.window.showErrorMessage(error instanceof Error ? error.message : String(error));
43
+ }
44
+ }
45
+
46
+ function writeIndexReport(output, logger, result) {
47
+ output.clear();
48
+ logger.info("indexing started");
49
+ logger.info(`${result.filesIndexed} files indexed`);
50
+ logger.info(`${result.written} artifacts written`);
51
+ logger.info(`${result.skippedLarge} skipped large files count`);
52
+ logger.info(`${result.ignored} ignored files count`);
53
+ output.show();
54
+ }
55
+
56
+ function activate(context) {
57
+ const output = vscode.window.createOutputChannel("Codex Context");
58
+
59
+ context.subscriptions.push(
60
+ output,
61
+ vscode.commands.registerCommand("codexContext.newProject", () => handleCommand(output, async (core) => {
62
+ const name = await vscode.window.showInputBox({ prompt: "Project name" });
63
+ if (!name) return;
64
+ const parent = workspaceRoot() ?? process.cwd();
65
+ const result = core.runNew(path.join(parent, name));
66
+ vscode.window.showInformationMessage(`Codex Context: created ${result.root}`);
67
+ })),
68
+ vscode.commands.registerCommand("codexContext.syncWorkspace", () => handleCommand(output, (core) => {
69
+ const result = core.runSync(requireWorkspace());
70
+ vscode.window.showInformationMessage(`Codex Context: created ${result.created} missing file(s)`);
71
+ })),
72
+ vscode.commands.registerCommand("codexContext.doctorWorkspace", () => handleCommand(output, (core) => {
73
+ const result = core.runProjectDoctor(requireWorkspace());
74
+ output.clear();
75
+ output.appendLine("Codex Context Doctor");
76
+ output.appendLine("");
77
+ for (const item of result.results) output.appendLine(item.line);
78
+ output.show();
79
+ })),
80
+ vscode.commands.registerCommand("codexContext.upgradeAgents", () => handleCommand(output, (core) => {
81
+ const result = core.runProjectUpgrade(requireWorkspace());
82
+ vscode.window.showInformationMessage(`Codex Context: ${result.action} .codex/AGENTS.md`);
83
+ })),
84
+ vscode.commands.registerCommand("codexContext.setupGlobal", () => handleCommand(output, (core) => {
85
+ const result = core.runGlobalSetup();
86
+ vscode.window.showInformationMessage(`Codex Context: ${result.action} global AGENTS.md`);
87
+ })),
88
+ vscode.commands.registerCommand("codexContext.doctorGlobal", () => handleCommand(output, (core) => {
89
+ const result = core.runGlobalDoctor();
90
+ output.clear();
91
+ output.appendLine("Codex Context Global Doctor");
92
+ output.appendLine("");
93
+ for (const item of result.results) output.appendLine(item.line);
94
+ output.show();
95
+ })),
96
+ vscode.commands.registerCommand("codexContext.indexWorkspace", () => handleCommand(output, (core, logger) => {
97
+ output.clear();
98
+ logger.info("indexing started");
99
+ output.show();
100
+ const result = core.runContextIndex(requireWorkspace(), { maxFileSizeKb: maxFileSizeKb() });
101
+ writeIndexReport(output, logger, result);
102
+ vscode.window.showInformationMessage("Codex Context: artifacts written");
103
+ })),
104
+ vscode.commands.registerCommand("codexContext.contextDoctor", () => handleCommand(output, (core) => {
105
+ const result = core.runContextDoctor(requireWorkspace());
106
+ output.clear();
107
+ output.appendLine("Codex Context Artifact Doctor");
108
+ output.appendLine("");
109
+ for (const item of result.results) output.appendLine(item.line);
110
+ output.show();
111
+ })),
112
+ vscode.commands.registerCommand("codexContext.queryRelevant", () => handleCommand(output, async (core) => {
113
+ const question = await vscode.window.showInputBox({ prompt: "What are you trying to change or understand?" });
114
+ if (!question) return;
115
+ const result = core.runQuery(requireWorkspace(), question);
116
+ output.clear();
117
+ output.appendLine("Codex Context Query");
118
+ output.appendLine("");
119
+ output.appendLine(`Query: ${result.question}`);
120
+ output.appendLine("");
121
+ for (const match of result.matches) output.appendLine(`${match.score} ${match.path}`);
122
+ output.show();
123
+ vscode.window.showInformationMessage("Codex Context: relevant context written");
124
+ }))
125
+ );
126
+
127
+ loadCore().then((core) => {
128
+ if (vscode.workspace.getConfiguration("codexContext").get("autoIndex", false)) {
129
+ const root = workspaceRoot();
130
+ if (root) {
131
+ const count = core.countEligibleFiles(root, { maxFileSizeKb: maxFileSizeKb() });
132
+ if (count < 1000) {
133
+ vscode.window.showInformationMessage("Index Codex Context now?", "Index").then((choice) => {
134
+ if (choice === "Index") vscode.commands.executeCommand("codexContext.indexWorkspace");
135
+ });
136
+ } else {
137
+ vscode.window.showInformationMessage("Use Codex Context: Index Current Workspace when ready.");
138
+ }
139
+ }
140
+ }
141
+
142
+ if (vscode.workspace.getConfiguration("codexContext").get("watch", false)) {
143
+ const root = workspaceRoot();
144
+ if (root) {
145
+ let timer;
146
+ const watcher = vscode.workspace.createFileSystemWatcher("**/*");
147
+ const schedule = (uri) => {
148
+ if (core.isIgnoredWorkspacePath(root, uri.fsPath)) return;
149
+ clearTimeout(timer);
150
+ timer = setTimeout(() => vscode.commands.executeCommand("codexContext.indexWorkspace"), 1000);
151
+ };
152
+ watcher.onDidCreate(schedule);
153
+ watcher.onDidChange(schedule);
154
+ watcher.onDidDelete(schedule);
155
+ context.subscriptions.push(watcher);
156
+ }
157
+ }
158
+ });
159
+ }
160
+
161
+ function deactivate() {}
162
+
163
+ module.exports = { activate, deactivate };
@@ -0,0 +1,141 @@
1
+ import path from "node:path";
2
+ import * as vscode from "vscode";
3
+ import {
4
+ countEligibleFiles,
5
+ isIgnoredWorkspacePath,
6
+ runContextDoctor,
7
+ runContextIndex,
8
+ runGlobalDoctor,
9
+ runGlobalSetup,
10
+ runNew,
11
+ runProjectDoctor,
12
+ runProjectUpgrade,
13
+ runSync
14
+ } from "./core.js";
15
+ import { createLogger } from "./core/logger.js";
16
+
17
+ function workspaceRoot() {
18
+ return vscode.workspace.workspaceFolders?.[0]?.uri.fsPath;
19
+ }
20
+
21
+ function requireWorkspace() {
22
+ const root = workspaceRoot();
23
+ if (!root) throw new Error("Open a workspace folder first.");
24
+ return root;
25
+ }
26
+
27
+ function maxFileSizeKb() {
28
+ return vscode.workspace.getConfiguration("codexContext").get("maxFileSizeKb", 300);
29
+ }
30
+
31
+ function writeIndexReport(output, logger, result) {
32
+ output.clear();
33
+ logger.info("indexing started");
34
+ logger.info(`${result.filesIndexed} files indexed`);
35
+ logger.info(`${result.written} artifacts written`);
36
+ logger.info(`${result.skippedLarge} skipped large files count`);
37
+ logger.info(`${result.ignored} ignored files count`);
38
+ output.show();
39
+ }
40
+
41
+ async function handleCommand(logger, action) {
42
+ try {
43
+ await action();
44
+ } catch (error) {
45
+ logger.error(error);
46
+ vscode.window.showErrorMessage(error instanceof Error ? error.message : String(error));
47
+ }
48
+ }
49
+
50
+ export function activate(context) {
51
+ const output = vscode.window.createOutputChannel("Codex Context");
52
+ const logger = createLogger({ sink: { log: (message) => output.appendLine(message), error: (message) => output.appendLine(message) } });
53
+
54
+ context.subscriptions.push(
55
+ output,
56
+ vscode.commands.registerCommand("codexContext.newProject", () => handleCommand(logger, async () => {
57
+ const name = await vscode.window.showInputBox({ prompt: "Project name" });
58
+ if (!name) return;
59
+ const parent = workspaceRoot() ?? process.cwd();
60
+ const result = runNew(path.join(parent, name));
61
+ vscode.window.showInformationMessage(`Codex Context: created ${result.root}`);
62
+ })),
63
+ vscode.commands.registerCommand("codexContext.syncWorkspace", () => handleCommand(logger, () => {
64
+ const result = runSync(requireWorkspace());
65
+ vscode.window.showInformationMessage(`Codex Context: created ${result.created} missing file(s)`);
66
+ })),
67
+ vscode.commands.registerCommand("codexContext.doctorWorkspace", () => handleCommand(logger, () => {
68
+ const result = runProjectDoctor(requireWorkspace());
69
+ output.clear();
70
+ output.appendLine("Codex Context Doctor");
71
+ output.appendLine("");
72
+ for (const item of result.results) output.appendLine(item.line);
73
+ output.show();
74
+ })),
75
+ vscode.commands.registerCommand("codexContext.upgradeAgents", () => handleCommand(logger, () => {
76
+ const result = runProjectUpgrade(requireWorkspace());
77
+ vscode.window.showInformationMessage(`Codex Context: ${result.action} .codex/AGENTS.md`);
78
+ })),
79
+ vscode.commands.registerCommand("codexContext.setupGlobal", () => handleCommand(logger, () => {
80
+ const result = runGlobalSetup();
81
+ vscode.window.showInformationMessage(`Codex Context: ${result.action} global AGENTS.md`);
82
+ })),
83
+ vscode.commands.registerCommand("codexContext.doctorGlobal", () => handleCommand(logger, () => {
84
+ const result = runGlobalDoctor();
85
+ output.clear();
86
+ output.appendLine("Codex Context Global Doctor");
87
+ output.appendLine("");
88
+ for (const item of result.results) output.appendLine(item.line);
89
+ output.show();
90
+ })),
91
+ vscode.commands.registerCommand("codexContext.indexWorkspace", () => handleCommand(logger, () => {
92
+ output.clear();
93
+ logger.info("indexing started");
94
+ output.show();
95
+ const result = runContextIndex(requireWorkspace(), { maxFileSizeKb: maxFileSizeKb() });
96
+ writeIndexReport(output, logger, result);
97
+ vscode.window.showInformationMessage("Codex Context: artifacts written");
98
+ })),
99
+ vscode.commands.registerCommand("codexContext.contextDoctor", () => handleCommand(logger, () => {
100
+ const result = runContextDoctor(requireWorkspace());
101
+ output.clear();
102
+ output.appendLine("Codex Context Artifact Doctor");
103
+ output.appendLine("");
104
+ for (const item of result.results) output.appendLine(item.line);
105
+ output.show();
106
+ }))
107
+ );
108
+
109
+ if (vscode.workspace.getConfiguration("codexContext").get("autoIndex", false)) {
110
+ const root = workspaceRoot();
111
+ if (root) {
112
+ const count = countEligibleFiles(root, { maxFileSizeKb: maxFileSizeKb() });
113
+ if (count < 1000) {
114
+ vscode.window.showInformationMessage("Index Codex Context now?", "Index").then((choice) => {
115
+ if (choice === "Index") vscode.commands.executeCommand("codexContext.indexWorkspace");
116
+ });
117
+ } else {
118
+ vscode.window.showInformationMessage("Use Codex Context: Index Current Workspace when ready.");
119
+ }
120
+ }
121
+ }
122
+
123
+ if (vscode.workspace.getConfiguration("codexContext").get("watch", false)) {
124
+ const root = workspaceRoot();
125
+ if (root) {
126
+ let timer;
127
+ const watcher = vscode.workspace.createFileSystemWatcher("**/*");
128
+ const schedule = (uri) => {
129
+ if (isIgnoredWorkspacePath(root, uri.fsPath)) return;
130
+ clearTimeout(timer);
131
+ timer = setTimeout(() => vscode.commands.executeCommand("codexContext.indexWorkspace"), 1000);
132
+ };
133
+ watcher.onDidCreate(schedule);
134
+ watcher.onDidChange(schedule);
135
+ watcher.onDidDelete(schedule);
136
+ context.subscriptions.push(watcher);
137
+ }
138
+ }
139
+ }
140
+
141
+ export function deactivate() {}