omo-suites 1.13.0 → 1.14.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/CHANGELOG.md +14 -0
- package/dist/cli/omocs.js +495 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,20 @@ All notable changes to OMO Suites will be documented in this file.
|
|
|
5
5
|
Format based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
6
6
|
This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.14.0] - 2026-03-26
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- **Auto system** — automatic background checks run on every `omocs` command (non-blocking)
|
|
12
|
+
- **Auto-Doctor** — workspace health check on first run per day (missing config, AGENTS.md, .gitignore)
|
|
13
|
+
- **Auto-Index** — rebuild workspace index when file structure changes (new/renamed files detected)
|
|
14
|
+
- **Auto-Compact** — periodic cleanup of stale memory, stats, and orphaned indexes (every 7 days)
|
|
15
|
+
- **Auto-Template Suggest** — detect empty projects and suggest matching saved templates
|
|
16
|
+
- `omocs auto run` — manually trigger all auto checks
|
|
17
|
+
- `omocs auto status` — view auto check state and timings
|
|
18
|
+
- `omocs auto reset` — force re-run all checks
|
|
19
|
+
- `omocs auto suppress <warning>` — hide specific warnings
|
|
20
|
+
- Auto checks are silent unless there are warnings or fixes to report
|
|
21
|
+
|
|
8
22
|
## [1.13.0] - 2026-03-26
|
|
9
23
|
|
|
10
24
|
### Added
|
package/dist/cli/omocs.js
CHANGED
|
@@ -41963,6 +41963,492 @@ var init_squad = __esm(() => {
|
|
|
41963
41963
|
SQUAD_STATE = join22(SQUAD_DIR, "state.json");
|
|
41964
41964
|
});
|
|
41965
41965
|
|
|
41966
|
+
// src/core/auto.ts
|
|
41967
|
+
import { existsSync as existsSync28, readFileSync as readFileSync29, writeFileSync as writeFileSync21, mkdirSync as mkdirSync17, statSync as statSync11, readdirSync as readdirSync11 } from "fs";
|
|
41968
|
+
import { join as join23, extname as extname2, basename as basename8 } from "path";
|
|
41969
|
+
import { homedir as homedir17 } from "os";
|
|
41970
|
+
import { createHash as createHash6 } from "crypto";
|
|
41971
|
+
function ensureDir5(dir) {
|
|
41972
|
+
if (!existsSync28(dir))
|
|
41973
|
+
mkdirSync17(dir, { recursive: true });
|
|
41974
|
+
}
|
|
41975
|
+
function readJsonSafe5(path2) {
|
|
41976
|
+
try {
|
|
41977
|
+
return JSON.parse(readFileSync29(path2, "utf-8"));
|
|
41978
|
+
} catch {
|
|
41979
|
+
return null;
|
|
41980
|
+
}
|
|
41981
|
+
}
|
|
41982
|
+
function getAutoState() {
|
|
41983
|
+
if (existsSync28(AUTO_STATE_FILE)) {
|
|
41984
|
+
const state2 = readJsonSafe5(AUTO_STATE_FILE);
|
|
41985
|
+
if (state2)
|
|
41986
|
+
return state2;
|
|
41987
|
+
}
|
|
41988
|
+
return {
|
|
41989
|
+
lastCompact: 0,
|
|
41990
|
+
lastIndex: {},
|
|
41991
|
+
lastDoctor: 0,
|
|
41992
|
+
structureHashes: {},
|
|
41993
|
+
suppressedWarnings: []
|
|
41994
|
+
};
|
|
41995
|
+
}
|
|
41996
|
+
function saveAutoState(state2) {
|
|
41997
|
+
ensureDir5(OMOCS_DIR2);
|
|
41998
|
+
writeFileSync21(AUTO_STATE_FILE, JSON.stringify(state2, null, 2), "utf-8");
|
|
41999
|
+
}
|
|
42000
|
+
function getWorkspaceHash3(cwd) {
|
|
42001
|
+
return createHash6("sha256").update(cwd).digest("hex").substring(0, 16);
|
|
42002
|
+
}
|
|
42003
|
+
function getStructureHash(cwd) {
|
|
42004
|
+
try {
|
|
42005
|
+
const entries = [];
|
|
42006
|
+
const scan = (dir, depth) => {
|
|
42007
|
+
if (depth > 2)
|
|
42008
|
+
return;
|
|
42009
|
+
const items = readdirSync11(dir, { withFileTypes: true });
|
|
42010
|
+
for (const item of items) {
|
|
42011
|
+
if (item.name.startsWith(".") || IGNORED_DIRS3.includes(item.name))
|
|
42012
|
+
continue;
|
|
42013
|
+
if (item.isDirectory()) {
|
|
42014
|
+
entries.push(`d:${item.name}`);
|
|
42015
|
+
scan(join23(dir, item.name), depth + 1);
|
|
42016
|
+
} else if (item.isFile() && WATCHED_EXTS2.includes(extname2(item.name))) {
|
|
42017
|
+
entries.push(`f:${item.name}`);
|
|
42018
|
+
}
|
|
42019
|
+
}
|
|
42020
|
+
};
|
|
42021
|
+
scan(cwd, 0);
|
|
42022
|
+
return createHash6("sha256").update(entries.join("|")).digest("hex").substring(0, 16);
|
|
42023
|
+
} catch {
|
|
42024
|
+
return "";
|
|
42025
|
+
}
|
|
42026
|
+
}
|
|
42027
|
+
function autoCompact(state2) {
|
|
42028
|
+
const results = [];
|
|
42029
|
+
const now = Date.now();
|
|
42030
|
+
if (now - state2.lastCompact < COMPACT_THRESHOLD_DAYS * 24 * 60 * 60 * 1000) {
|
|
42031
|
+
return results;
|
|
42032
|
+
}
|
|
42033
|
+
if (existsSync28(MEMORY_DIR3)) {
|
|
42034
|
+
try {
|
|
42035
|
+
const files = readdirSync11(MEMORY_DIR3).filter((f) => f.endsWith(".json"));
|
|
42036
|
+
let totalEntries = 0;
|
|
42037
|
+
let totalSize = 0;
|
|
42038
|
+
for (const file of files) {
|
|
42039
|
+
const filePath = join23(MEMORY_DIR3, file);
|
|
42040
|
+
totalSize += statSync11(filePath).size;
|
|
42041
|
+
const data = readJsonSafe5(filePath);
|
|
42042
|
+
if (data && Array.isArray(data.notes))
|
|
42043
|
+
totalEntries += data.notes.length;
|
|
42044
|
+
}
|
|
42045
|
+
if (totalEntries > COMPACT_MEMORY_MAX_ENTRIES) {
|
|
42046
|
+
for (const file of files) {
|
|
42047
|
+
const filePath = join23(MEMORY_DIR3, file);
|
|
42048
|
+
const data = readJsonSafe5(filePath);
|
|
42049
|
+
if (data && Array.isArray(data.notes) && data.notes.length > COMPACT_MEMORY_MAX_ENTRIES) {
|
|
42050
|
+
const archiveDir = join23(MEMORY_DIR3, "archive");
|
|
42051
|
+
ensureDir5(archiveDir);
|
|
42052
|
+
const removed = data.notes.splice(0, data.notes.length - COMPACT_MEMORY_MAX_ENTRIES);
|
|
42053
|
+
writeFileSync21(join23(archiveDir, `${basename8(file, ".json")}-auto-${now}.json`), JSON.stringify({ archived: new Date().toISOString(), notes: removed }, null, 2), "utf-8");
|
|
42054
|
+
writeFileSync21(filePath, JSON.stringify(data, null, 2), "utf-8");
|
|
42055
|
+
}
|
|
42056
|
+
}
|
|
42057
|
+
results.push({ action: "auto-compact-memory", status: "fixed", message: `Trimmed memory (${totalEntries} entries → ${COMPACT_MEMORY_MAX_ENTRIES} max per file)` });
|
|
42058
|
+
} else {
|
|
42059
|
+
results.push({ action: "auto-compact-memory", status: "ok", message: `Memory clean (${totalEntries} entries)` });
|
|
42060
|
+
}
|
|
42061
|
+
} catch {}
|
|
42062
|
+
}
|
|
42063
|
+
if (existsSync28(STATS_FILE2)) {
|
|
42064
|
+
try {
|
|
42065
|
+
const data = readJsonSafe5(STATS_FILE2);
|
|
42066
|
+
if (data && data.daily) {
|
|
42067
|
+
const cutoff = now - COMPACT_STATS_MAX_DAYS * 24 * 60 * 60 * 1000;
|
|
42068
|
+
const dates = Object.keys(data.daily);
|
|
42069
|
+
const old = dates.filter((d) => new Date(d).getTime() < cutoff);
|
|
42070
|
+
if (old.length > 0) {
|
|
42071
|
+
const archiveDir = join23(OMOCS_DIR2, "stats-archive");
|
|
42072
|
+
ensureDir5(archiveDir);
|
|
42073
|
+
const archived = {};
|
|
42074
|
+
for (const d of old) {
|
|
42075
|
+
archived[d] = data.daily[d];
|
|
42076
|
+
delete data.daily[d];
|
|
42077
|
+
}
|
|
42078
|
+
writeFileSync21(join23(archiveDir, `stats-auto-${now}.json`), JSON.stringify({ archivedAt: new Date().toISOString(), daily: archived }, null, 2), "utf-8");
|
|
42079
|
+
writeFileSync21(STATS_FILE2, JSON.stringify(data, null, 2), "utf-8");
|
|
42080
|
+
results.push({ action: "auto-compact-stats", status: "fixed", message: `Archived ${old.length} old stats entries` });
|
|
42081
|
+
}
|
|
42082
|
+
}
|
|
42083
|
+
} catch {}
|
|
42084
|
+
}
|
|
42085
|
+
if (existsSync28(INDEX_DIR3)) {
|
|
42086
|
+
try {
|
|
42087
|
+
const dirs = readdirSync11(INDEX_DIR3).filter((d) => {
|
|
42088
|
+
const p = join23(INDEX_DIR3, d);
|
|
42089
|
+
return statSync11(p).isDirectory();
|
|
42090
|
+
});
|
|
42091
|
+
let orphaned = 0;
|
|
42092
|
+
for (const dir of dirs) {
|
|
42093
|
+
const indexPath = join23(INDEX_DIR3, dir, "index.json");
|
|
42094
|
+
if (!existsSync28(indexPath))
|
|
42095
|
+
continue;
|
|
42096
|
+
const data = readJsonSafe5(indexPath);
|
|
42097
|
+
if (data && data.path && !existsSync28(data.path)) {
|
|
42098
|
+
const { unlinkSync: unlinkSync6 } = __require("fs");
|
|
42099
|
+
unlinkSync6(indexPath);
|
|
42100
|
+
orphaned++;
|
|
42101
|
+
}
|
|
42102
|
+
}
|
|
42103
|
+
if (orphaned > 0) {
|
|
42104
|
+
results.push({ action: "auto-compact-index", status: "fixed", message: `Removed ${orphaned} orphaned index(es)` });
|
|
42105
|
+
}
|
|
42106
|
+
} catch {}
|
|
42107
|
+
}
|
|
42108
|
+
state2.lastCompact = now;
|
|
42109
|
+
return results;
|
|
42110
|
+
}
|
|
42111
|
+
function autoIndex(cwd, state2) {
|
|
42112
|
+
const results = [];
|
|
42113
|
+
const wsHash = getWorkspaceHash3(cwd);
|
|
42114
|
+
const now = Date.now();
|
|
42115
|
+
const lastIndexTime = state2.lastIndex[wsHash] || 0;
|
|
42116
|
+
if (now - lastIndexTime < INDEX_STALE_HOURS * 60 * 60 * 1000) {
|
|
42117
|
+
return results;
|
|
42118
|
+
}
|
|
42119
|
+
const currentHash = getStructureHash(cwd);
|
|
42120
|
+
const lastHash = state2.structureHashes[wsHash] || "";
|
|
42121
|
+
if (currentHash && currentHash !== lastHash) {
|
|
42122
|
+
try {
|
|
42123
|
+
const indexDir = join23(INDEX_DIR3, wsHash);
|
|
42124
|
+
ensureDir5(indexDir);
|
|
42125
|
+
const techStack = [];
|
|
42126
|
+
const keyFiles = [];
|
|
42127
|
+
let fileCount = 0;
|
|
42128
|
+
const scan = (dir, depth) => {
|
|
42129
|
+
if (depth > 3)
|
|
42130
|
+
return;
|
|
42131
|
+
try {
|
|
42132
|
+
const items = readdirSync11(dir, { withFileTypes: true });
|
|
42133
|
+
for (const item of items) {
|
|
42134
|
+
if (item.name.startsWith(".") || IGNORED_DIRS3.includes(item.name))
|
|
42135
|
+
continue;
|
|
42136
|
+
if (item.isDirectory())
|
|
42137
|
+
scan(join23(dir, item.name), depth + 1);
|
|
42138
|
+
else if (item.isFile()) {
|
|
42139
|
+
fileCount++;
|
|
42140
|
+
const ext = extname2(item.name);
|
|
42141
|
+
if (ext === ".ts" || ext === ".tsx") {
|
|
42142
|
+
if (!techStack.includes("TypeScript"))
|
|
42143
|
+
techStack.push("TypeScript");
|
|
42144
|
+
}
|
|
42145
|
+
if (ext === ".py") {
|
|
42146
|
+
if (!techStack.includes("Python"))
|
|
42147
|
+
techStack.push("Python");
|
|
42148
|
+
}
|
|
42149
|
+
if (ext === ".go") {
|
|
42150
|
+
if (!techStack.includes("Go"))
|
|
42151
|
+
techStack.push("Go");
|
|
42152
|
+
}
|
|
42153
|
+
if (ext === ".rs") {
|
|
42154
|
+
if (!techStack.includes("Rust"))
|
|
42155
|
+
techStack.push("Rust");
|
|
42156
|
+
}
|
|
42157
|
+
if ([
|
|
42158
|
+
"package.json",
|
|
42159
|
+
"tsconfig.json",
|
|
42160
|
+
"Cargo.toml",
|
|
42161
|
+
"go.mod",
|
|
42162
|
+
"pyproject.toml",
|
|
42163
|
+
"Dockerfile",
|
|
42164
|
+
"docker-compose.yml",
|
|
42165
|
+
"next.config.ts",
|
|
42166
|
+
"next.config.js",
|
|
42167
|
+
"nest-cli.json",
|
|
42168
|
+
"opencode.json",
|
|
42169
|
+
"AGENTS.md"
|
|
42170
|
+
].includes(item.name)) {
|
|
42171
|
+
keyFiles.push(join23(dir, item.name));
|
|
42172
|
+
}
|
|
42173
|
+
}
|
|
42174
|
+
}
|
|
42175
|
+
} catch {}
|
|
42176
|
+
};
|
|
42177
|
+
scan(cwd, 0);
|
|
42178
|
+
const index = {
|
|
42179
|
+
id: wsHash,
|
|
42180
|
+
path: cwd,
|
|
42181
|
+
builtAt: new Date().toISOString(),
|
|
42182
|
+
techStack,
|
|
42183
|
+
fileCount,
|
|
42184
|
+
keyFiles: keyFiles.map((f) => f.replace(cwd, ".")),
|
|
42185
|
+
autoBuilt: true
|
|
42186
|
+
};
|
|
42187
|
+
writeFileSync21(join23(indexDir, "index.json"), JSON.stringify(index, null, 2), "utf-8");
|
|
42188
|
+
state2.lastIndex[wsHash] = now;
|
|
42189
|
+
state2.structureHashes[wsHash] = currentHash;
|
|
42190
|
+
results.push({ action: "auto-index", status: "fixed", message: `Index rebuilt (${fileCount} files, ${techStack.join("/")})` });
|
|
42191
|
+
} catch {}
|
|
42192
|
+
}
|
|
42193
|
+
return results;
|
|
42194
|
+
}
|
|
42195
|
+
function autoDoctor(cwd, state2) {
|
|
42196
|
+
const results = [];
|
|
42197
|
+
const now = Date.now();
|
|
42198
|
+
if (now - state2.lastDoctor < 24 * 60 * 60 * 1000)
|
|
42199
|
+
return results;
|
|
42200
|
+
const warnings = [];
|
|
42201
|
+
const configLocations = ["opencode.json", join23(".opencode", "opencode.json")];
|
|
42202
|
+
const hasConfig = configLocations.some((l) => existsSync28(join23(cwd, l)));
|
|
42203
|
+
if (!hasConfig) {
|
|
42204
|
+
warnings.push("No opencode.json found — run `omocs init` to set up");
|
|
42205
|
+
}
|
|
42206
|
+
if (!existsSync28(join23(cwd, "AGENTS.md"))) {
|
|
42207
|
+
warnings.push("No AGENTS.md — run `omocs watch generate` or `omocs init-deep`");
|
|
42208
|
+
}
|
|
42209
|
+
const gitignorePath = join23(cwd, ".gitignore");
|
|
42210
|
+
if (existsSync28(gitignorePath)) {
|
|
42211
|
+
const gitignore = readFileSync29(gitignorePath, "utf-8");
|
|
42212
|
+
if (!gitignore.includes(".opencode")) {
|
|
42213
|
+
warnings.push(".opencode not in .gitignore — sessions/cache may be committed");
|
|
42214
|
+
}
|
|
42215
|
+
}
|
|
42216
|
+
if (existsSync28(OMOCS_DIR2)) {
|
|
42217
|
+
try {
|
|
42218
|
+
let totalSize = 0;
|
|
42219
|
+
const checkSize = (dir) => {
|
|
42220
|
+
const items = readdirSync11(dir, { withFileTypes: true });
|
|
42221
|
+
for (const item of items) {
|
|
42222
|
+
const p = join23(dir, item.name);
|
|
42223
|
+
if (item.isFile())
|
|
42224
|
+
totalSize += statSync11(p).size;
|
|
42225
|
+
else if (item.isDirectory())
|
|
42226
|
+
checkSize(p);
|
|
42227
|
+
}
|
|
42228
|
+
};
|
|
42229
|
+
checkSize(OMOCS_DIR2);
|
|
42230
|
+
if (totalSize > 50 * 1024 * 1024) {
|
|
42231
|
+
warnings.push(`~/.omocs is ${(totalSize / 1024 / 1024).toFixed(0)}MB — run \`omocs compact all --fix\``);
|
|
42232
|
+
}
|
|
42233
|
+
} catch {}
|
|
42234
|
+
}
|
|
42235
|
+
const unsuppressed = warnings.filter((w) => !state2.suppressedWarnings.includes(w));
|
|
42236
|
+
if (unsuppressed.length > 0) {
|
|
42237
|
+
results.push({
|
|
42238
|
+
action: "auto-doctor",
|
|
42239
|
+
status: "warn",
|
|
42240
|
+
message: unsuppressed.join("; ")
|
|
42241
|
+
});
|
|
42242
|
+
} else {
|
|
42243
|
+
results.push({ action: "auto-doctor", status: "ok", message: "Workspace healthy" });
|
|
42244
|
+
}
|
|
42245
|
+
state2.lastDoctor = now;
|
|
42246
|
+
return results;
|
|
42247
|
+
}
|
|
42248
|
+
function autoTemplateSuggest(cwd, state2) {
|
|
42249
|
+
const results = [];
|
|
42250
|
+
const configLocations = ["opencode.json", join23(".opencode", "opencode.json")];
|
|
42251
|
+
const hasConfig = configLocations.some((l) => existsSync28(join23(cwd, l)));
|
|
42252
|
+
if (hasConfig)
|
|
42253
|
+
return results;
|
|
42254
|
+
if (!existsSync28(TEMPLATE_DIR2))
|
|
42255
|
+
return results;
|
|
42256
|
+
try {
|
|
42257
|
+
const templates = readdirSync11(TEMPLATE_DIR2).filter((d) => {
|
|
42258
|
+
const manifestPath = join23(TEMPLATE_DIR2, d, "manifest.json");
|
|
42259
|
+
return existsSync28(manifestPath);
|
|
42260
|
+
});
|
|
42261
|
+
if (templates.length > 0) {
|
|
42262
|
+
let projectType = "unknown";
|
|
42263
|
+
if (existsSync28(join23(cwd, "package.json"))) {
|
|
42264
|
+
const pkg = readJsonSafe5(join23(cwd, "package.json"));
|
|
42265
|
+
if (pkg) {
|
|
42266
|
+
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
42267
|
+
if (deps["next"])
|
|
42268
|
+
projectType = "nextjs";
|
|
42269
|
+
else if (deps["@nestjs/core"])
|
|
42270
|
+
projectType = "nestjs";
|
|
42271
|
+
else if (deps["react"])
|
|
42272
|
+
projectType = "react";
|
|
42273
|
+
else if (deps["vue"])
|
|
42274
|
+
projectType = "vue";
|
|
42275
|
+
else
|
|
42276
|
+
projectType = "node";
|
|
42277
|
+
}
|
|
42278
|
+
} else if (existsSync28(join23(cwd, "Cargo.toml")))
|
|
42279
|
+
projectType = "rust";
|
|
42280
|
+
else if (existsSync28(join23(cwd, "go.mod")))
|
|
42281
|
+
projectType = "go";
|
|
42282
|
+
else if (existsSync28(join23(cwd, "pyproject.toml")))
|
|
42283
|
+
projectType = "python";
|
|
42284
|
+
for (const t of templates) {
|
|
42285
|
+
const manifest = readJsonSafe5(join23(TEMPLATE_DIR2, t, "manifest.json"));
|
|
42286
|
+
if (manifest && manifest.tags) {
|
|
42287
|
+
const tags = manifest.tags;
|
|
42288
|
+
if (tags.includes(projectType) || tags.includes("fullstack")) {
|
|
42289
|
+
results.push({
|
|
42290
|
+
action: "auto-template",
|
|
42291
|
+
status: "warn",
|
|
42292
|
+
message: `Template "${manifest.name}" matches this ${projectType} project → omocs template load ${manifest.name}`
|
|
42293
|
+
});
|
|
42294
|
+
break;
|
|
42295
|
+
}
|
|
42296
|
+
}
|
|
42297
|
+
}
|
|
42298
|
+
}
|
|
42299
|
+
} catch {}
|
|
42300
|
+
return results;
|
|
42301
|
+
}
|
|
42302
|
+
async function runAutoChecks(cwd, opts) {
|
|
42303
|
+
const state2 = getAutoState();
|
|
42304
|
+
const allResults = [];
|
|
42305
|
+
allResults.push(...autoDoctor(cwd, state2));
|
|
42306
|
+
allResults.push(...autoIndex(cwd, state2));
|
|
42307
|
+
if (!opts?.skipCompact) {
|
|
42308
|
+
allResults.push(...autoCompact(state2));
|
|
42309
|
+
}
|
|
42310
|
+
allResults.push(...autoTemplateSuggest(cwd, state2));
|
|
42311
|
+
saveAutoState(state2);
|
|
42312
|
+
if (!opts?.silent) {
|
|
42313
|
+
const warnings = allResults.filter((r) => r.status === "warn");
|
|
42314
|
+
const fixes = allResults.filter((r) => r.status === "fixed");
|
|
42315
|
+
if (warnings.length > 0 || fixes.length > 0) {
|
|
42316
|
+
console.log(source_default.dim(" ── omocs auto ──"));
|
|
42317
|
+
for (const r of fixes) {
|
|
42318
|
+
console.log(` ${source_default.green("⚡")} ${source_default.dim(r.message)}`);
|
|
42319
|
+
}
|
|
42320
|
+
for (const r of warnings) {
|
|
42321
|
+
console.log(` ${source_default.yellow("⚠")} ${source_default.dim(r.message)}`);
|
|
42322
|
+
}
|
|
42323
|
+
console.log("");
|
|
42324
|
+
}
|
|
42325
|
+
}
|
|
42326
|
+
return allResults;
|
|
42327
|
+
}
|
|
42328
|
+
function suppressWarning(warning) {
|
|
42329
|
+
const state2 = getAutoState();
|
|
42330
|
+
if (!state2.suppressedWarnings.includes(warning)) {
|
|
42331
|
+
state2.suppressedWarnings.push(warning);
|
|
42332
|
+
saveAutoState(state2);
|
|
42333
|
+
}
|
|
42334
|
+
}
|
|
42335
|
+
function resetAutoState() {
|
|
42336
|
+
const state2 = {
|
|
42337
|
+
lastCompact: 0,
|
|
42338
|
+
lastIndex: {},
|
|
42339
|
+
lastDoctor: 0,
|
|
42340
|
+
structureHashes: {},
|
|
42341
|
+
suppressedWarnings: []
|
|
42342
|
+
};
|
|
42343
|
+
saveAutoState(state2);
|
|
42344
|
+
}
|
|
42345
|
+
var OMOCS_DIR2, AUTO_STATE_FILE, INDEX_DIR3, MEMORY_DIR3, STATS_FILE2, TEMPLATE_DIR2, COMPACT_THRESHOLD_DAYS = 7, COMPACT_MEMORY_MAX_ENTRIES = 100, COMPACT_STATS_MAX_DAYS = 60, INDEX_STALE_HOURS = 24, IGNORED_DIRS3, WATCHED_EXTS2;
|
|
42346
|
+
var init_auto = __esm(() => {
|
|
42347
|
+
init_source();
|
|
42348
|
+
OMOCS_DIR2 = join23(homedir17(), ".omocs");
|
|
42349
|
+
AUTO_STATE_FILE = join23(OMOCS_DIR2, "auto-state.json");
|
|
42350
|
+
INDEX_DIR3 = join23(OMOCS_DIR2, "workspaces");
|
|
42351
|
+
MEMORY_DIR3 = join23(OMOCS_DIR2, "memory");
|
|
42352
|
+
STATS_FILE2 = join23(OMOCS_DIR2, "stats.json");
|
|
42353
|
+
TEMPLATE_DIR2 = join23(OMOCS_DIR2, "templates");
|
|
42354
|
+
IGNORED_DIRS3 = ["node_modules", ".git", "dist", "build", ".next", "__pycache__", "coverage", ".opencode", ".venv", "vendor"];
|
|
42355
|
+
WATCHED_EXTS2 = [".ts", ".tsx", ".js", ".jsx", ".py", ".go", ".rs", ".java", ".rb", ".php", ".vue", ".svelte"];
|
|
42356
|
+
});
|
|
42357
|
+
|
|
42358
|
+
// src/commands/auto.ts
|
|
42359
|
+
function registerAutoCommand(program2) {
|
|
42360
|
+
const auto = program2.command("auto").description("Manage automatic background checks (doctor, index, compact, template)");
|
|
42361
|
+
auto.command("run").description("Run all auto checks now").option("--verbose", "Show all results including OK statuses").action(async (opts) => {
|
|
42362
|
+
try {
|
|
42363
|
+
heading("⚡ Auto Checks");
|
|
42364
|
+
info(`Workspace: ${source_default.gray(process.cwd())}`);
|
|
42365
|
+
console.log("");
|
|
42366
|
+
const results = await runAutoChecks(process.cwd(), { silent: true });
|
|
42367
|
+
if (results.length === 0) {
|
|
42368
|
+
success("Nothing to check.");
|
|
42369
|
+
return;
|
|
42370
|
+
}
|
|
42371
|
+
for (const r of results) {
|
|
42372
|
+
if (r.status === "ok" && !opts.verbose)
|
|
42373
|
+
continue;
|
|
42374
|
+
const icon = r.status === "ok" ? source_default.green("✅") : r.status === "fixed" ? source_default.green("⚡") : source_default.yellow("⚠️");
|
|
42375
|
+
console.log(` ${icon} ${source_default.bold(r.action)} — ${r.message}`);
|
|
42376
|
+
}
|
|
42377
|
+
const ok = results.filter((r) => r.status === "ok").length;
|
|
42378
|
+
const fixed = results.filter((r) => r.status === "fixed").length;
|
|
42379
|
+
const warned = results.filter((r) => r.status === "warn").length;
|
|
42380
|
+
console.log("");
|
|
42381
|
+
info(`OK: ${ok} | Fixed: ${fixed} | Warnings: ${warned}`);
|
|
42382
|
+
} catch (err) {
|
|
42383
|
+
handleError(err);
|
|
42384
|
+
}
|
|
42385
|
+
});
|
|
42386
|
+
auto.command("reset").description("Reset auto state (force re-run all checks)").action(() => {
|
|
42387
|
+
try {
|
|
42388
|
+
resetAutoState();
|
|
42389
|
+
success("Auto state reset. All checks will re-run on next invocation.");
|
|
42390
|
+
} catch (err) {
|
|
42391
|
+
handleError(err);
|
|
42392
|
+
}
|
|
42393
|
+
});
|
|
42394
|
+
auto.command("suppress <warning>").description("Suppress a specific auto warning").action((warning) => {
|
|
42395
|
+
try {
|
|
42396
|
+
suppressWarning(warning);
|
|
42397
|
+
success(`Suppressed: "${warning}"`);
|
|
42398
|
+
} catch (err) {
|
|
42399
|
+
handleError(err);
|
|
42400
|
+
}
|
|
42401
|
+
});
|
|
42402
|
+
auto.command("status").description("Show auto check state").action(() => {
|
|
42403
|
+
try {
|
|
42404
|
+
heading("⚡ Auto Status");
|
|
42405
|
+
const { existsSync: existsSync29, readFileSync: readFileSync30 } = __require("fs");
|
|
42406
|
+
const { join: join24 } = __require("path");
|
|
42407
|
+
const { homedir: homedir18 } = __require("os");
|
|
42408
|
+
const stateFile = join24(homedir18(), ".omocs", "auto-state.json");
|
|
42409
|
+
if (!existsSync29(stateFile)) {
|
|
42410
|
+
info("No auto state yet. Run `omocs auto run` to initialize.");
|
|
42411
|
+
return;
|
|
42412
|
+
}
|
|
42413
|
+
const state2 = JSON.parse(readFileSync30(stateFile, "utf-8"));
|
|
42414
|
+
const formatTime2 = (ts) => ts ? new Date(ts).toLocaleString() : "never";
|
|
42415
|
+
console.log(` ${source_default.dim("Last compact:")} ${formatTime2(state2.lastCompact)}`);
|
|
42416
|
+
console.log(` ${source_default.dim("Last doctor:")} ${formatTime2(state2.lastDoctor)}`);
|
|
42417
|
+
console.log(` ${source_default.dim("Indexed workspaces:")} ${Object.keys(state2.lastIndex || {}).length}`);
|
|
42418
|
+
console.log(` ${source_default.dim("Suppressed warnings:")} ${(state2.suppressedWarnings || []).length}`);
|
|
42419
|
+
if (state2.suppressedWarnings?.length > 0) {
|
|
42420
|
+
console.log("");
|
|
42421
|
+
info("Suppressed:");
|
|
42422
|
+
for (const w of state2.suppressedWarnings) {
|
|
42423
|
+
console.log(` ${source_default.gray("•")} ${source_default.dim(w)}`);
|
|
42424
|
+
}
|
|
42425
|
+
}
|
|
42426
|
+
} catch (err) {
|
|
42427
|
+
handleError(err);
|
|
42428
|
+
}
|
|
42429
|
+
});
|
|
42430
|
+
auto.action(() => {
|
|
42431
|
+
heading("⚡ Auto Checks");
|
|
42432
|
+
infoBox("Auto", [
|
|
42433
|
+
"Automatic background checks run on every omocs command.",
|
|
42434
|
+
"",
|
|
42435
|
+
` ${source_default.cyan("omocs auto run")} — run all checks now`,
|
|
42436
|
+
` ${source_default.cyan("omocs auto status")} — show check state`,
|
|
42437
|
+
` ${source_default.cyan("omocs auto reset")} — force re-run all`,
|
|
42438
|
+
` ${source_default.cyan("omocs auto suppress")} — hide a warning`,
|
|
42439
|
+
"",
|
|
42440
|
+
"Checks: doctor, index rebuild, compact, template suggest",
|
|
42441
|
+
"Auto-runs on startup (non-blocking, max every 24h)."
|
|
42442
|
+
].join(`
|
|
42443
|
+
`));
|
|
42444
|
+
});
|
|
42445
|
+
}
|
|
42446
|
+
var init_auto2 = __esm(() => {
|
|
42447
|
+
init_source();
|
|
42448
|
+
init_auto();
|
|
42449
|
+
init_ui();
|
|
42450
|
+
});
|
|
42451
|
+
|
|
41966
42452
|
// src/index.ts
|
|
41967
42453
|
var exports_src = {};
|
|
41968
42454
|
__export(exports_src, {
|
|
@@ -42000,17 +42486,24 @@ var init_src = __esm(() => {
|
|
|
42000
42486
|
init_watch();
|
|
42001
42487
|
init_marketplace();
|
|
42002
42488
|
init_squad();
|
|
42489
|
+
init_auto2();
|
|
42490
|
+
init_auto();
|
|
42003
42491
|
init_find_package_json();
|
|
42004
42492
|
pkg = readPackageJson(import.meta.url);
|
|
42005
42493
|
VERSION3 = pkg.version;
|
|
42006
42494
|
program2 = new Command;
|
|
42007
|
-
program2.name("omocs").description("OMO Suites — CLI toolkit for OpenCode power users").version(VERSION3, "-v, --version", "Show version").hook("preAction", () => {
|
|
42495
|
+
program2.name("omocs").description("OMO Suites — CLI toolkit for OpenCode power users").version(VERSION3, "-v, --version", "Show version").hook("preAction", (thisCommand) => {
|
|
42008
42496
|
process.on("uncaughtException", (error) => {
|
|
42009
42497
|
handleError(error);
|
|
42010
42498
|
});
|
|
42011
42499
|
process.on("unhandledRejection", (error) => {
|
|
42012
42500
|
handleError(error);
|
|
42013
42501
|
});
|
|
42502
|
+
const cmdName = thisCommand.args?.[0] || thisCommand.name();
|
|
42503
|
+
const skipAuto = ["auto", "completion", "help"].includes(cmdName);
|
|
42504
|
+
if (!skipAuto) {
|
|
42505
|
+
runAutoChecks(process.cwd(), { silent: false }).catch(() => {});
|
|
42506
|
+
}
|
|
42014
42507
|
});
|
|
42015
42508
|
registerInitCommand(program2);
|
|
42016
42509
|
registerDoctorCommand(program2);
|
|
@@ -42041,6 +42534,7 @@ var init_src = __esm(() => {
|
|
|
42041
42534
|
registerWatchCommand(program2);
|
|
42042
42535
|
registerMarketplaceCommand(program2);
|
|
42043
42536
|
registerSquadCommand(program2);
|
|
42537
|
+
registerAutoCommand(program2);
|
|
42044
42538
|
program2.action(() => {
|
|
42045
42539
|
showBanner();
|
|
42046
42540
|
program2.help();
|
package/package.json
CHANGED