nomoreide 0.1.95 → 0.1.97
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/cli/profile.js +12 -8
- package/dist/cli/profile.js.map +1 -1
- package/dist/core/agent-env/claude-reader.js +12 -4
- package/dist/core/agent-env/claude-reader.js.map +1 -1
- package/dist/core/agent-env/codex-reader.js +5 -4
- package/dist/core/agent-env/codex-reader.js.map +1 -1
- package/dist/core/agent-env/managed-plugins.d.ts +5 -0
- package/dist/core/agent-env/managed-plugins.js +43 -11
- package/dist/core/agent-env/managed-plugins.js.map +1 -1
- package/dist/core/agent-env-plugin-uninstall.js +36 -19
- package/dist/core/agent-env-plugin-uninstall.js.map +1 -1
- package/dist/core/agent-profiles/apply.d.ts +6 -1
- package/dist/core/agent-profiles/apply.js +37 -1
- package/dist/core/agent-profiles/apply.js.map +1 -1
- package/dist/core/agent-profiles/index.d.ts +3 -2
- package/dist/core/agent-profiles/index.js +3 -2
- package/dist/core/agent-profiles/index.js.map +1 -1
- package/dist/core/agent-profiles/plugin-apply.d.ts +16 -0
- package/dist/core/agent-profiles/plugin-apply.js +383 -0
- package/dist/core/agent-profiles/plugin-apply.js.map +1 -0
- package/dist/core/agent-profiles/plugin-bundle.d.ts +6 -0
- package/dist/core/agent-profiles/plugin-bundle.js +32 -0
- package/dist/core/agent-profiles/plugin-bundle.js.map +1 -0
- package/dist/core/agent-profiles/registry-transfer.js +6 -1
- package/dist/core/agent-profiles/registry-transfer.js.map +1 -1
- package/dist/core/agent-profiles/store.d.ts +3 -1
- package/dist/core/agent-profiles/store.js +92 -5
- package/dist/core/agent-profiles/store.js.map +1 -1
- package/dist/core/agent-profiles/transfer.d.ts +1 -0
- package/dist/core/agent-profiles/transfer.js +183 -5
- package/dist/core/agent-profiles/transfer.js.map +1 -1
- package/dist/core/agent-profiles/types.d.ts +105 -3
- package/dist/core/agent-profiles/types.js +15 -1
- package/dist/core/agent-profiles/types.js.map +1 -1
- package/dist/core/agent-sessions.d.ts +1 -1
- package/dist/core/agent-sessions.js +5 -0
- package/dist/core/agent-sessions.js.map +1 -1
- package/dist/core/agent-transcripts.d.ts +6 -4
- package/dist/core/agent-transcripts.js +20 -12
- package/dist/core/agent-transcripts.js.map +1 -1
- package/dist/core/config-store.d.ts +1 -0
- package/dist/core/config-store.js +24 -1
- package/dist/core/config-store.js.map +1 -1
- package/dist/core/docker-stats.d.ts +2 -0
- package/dist/core/docker-stats.js +24 -0
- package/dist/core/docker-stats.js.map +1 -1
- package/dist/core/git-worktrees.d.ts +34 -0
- package/dist/core/git-worktrees.js +132 -0
- package/dist/core/git-worktrees.js.map +1 -0
- package/dist/core/metrics-store.d.ts +11 -1
- package/dist/core/metrics-store.js +63 -5
- package/dist/core/metrics-store.js.map +1 -1
- package/dist/core/one-time-skills.d.ts +27 -0
- package/dist/core/one-time-skills.js +185 -0
- package/dist/core/one-time-skills.js.map +1 -0
- package/dist/core/system-processes.d.ts +29 -0
- package/dist/core/system-processes.js +119 -0
- package/dist/core/system-processes.js.map +1 -0
- package/dist/core/types.d.ts +3 -0
- package/dist/mcp/tools/agent-profiles.js +42 -10
- package/dist/mcp/tools/agent-profiles.js.map +1 -1
- package/dist/mcp/tools/git.d.ts +1 -1
- package/dist/mcp/tools/git.js +45 -0
- package/dist/mcp/tools/git.js.map +1 -1
- package/dist/mcp/tools/index.d.ts +1 -1
- package/dist/web/client/assets/{code-editor-Bx0wTXnf.js → code-editor-Bv3tCQrj.js} +1 -1
- package/dist/web/client/assets/index-BeJHDwLO.css +1 -0
- package/dist/web/client/assets/index-zb3rhV5y.js +308 -0
- package/dist/web/client/assets/system-process-table-q3WxburN.js +1 -0
- package/dist/web/client/index.html +2 -2
- package/dist/web/dashboard.js +11 -2
- package/dist/web/dashboard.js.map +1 -1
- package/dist/web/routes/agent-profile-routes.js +2 -1
- package/dist/web/routes/agent-profile-routes.js.map +1 -1
- package/dist/web/routes/git-routes.js +127 -4
- package/dist/web/routes/git-routes.js.map +1 -1
- package/dist/web/routes/index.js +2 -0
- package/dist/web/routes/index.js.map +1 -1
- package/dist/web/routes/metrics-routes.js +30 -4
- package/dist/web/routes/metrics-routes.js.map +1 -1
- package/dist/web/routes/skills-routes.d.ts +2 -0
- package/dist/web/routes/skills-routes.js +49 -0
- package/dist/web/routes/skills-routes.js.map +1 -0
- package/dist/web/routes/terminal-routes.js +33 -5
- package/dist/web/routes/terminal-routes.js.map +1 -1
- package/package.json +2 -1
- package/dist/web/client/assets/index-4ajqnD37.css +0 -1
- package/dist/web/client/assets/index-CpWMLRYx.js +0 -242
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export interface GitWorktree {
|
|
2
|
+
path: string;
|
|
3
|
+
head: string;
|
|
4
|
+
branch?: string;
|
|
5
|
+
bare: boolean;
|
|
6
|
+
detached: boolean;
|
|
7
|
+
locked: boolean;
|
|
8
|
+
lockedReason?: string;
|
|
9
|
+
prunable: boolean;
|
|
10
|
+
prunableReason?: string;
|
|
11
|
+
primary: boolean;
|
|
12
|
+
dirty: boolean;
|
|
13
|
+
}
|
|
14
|
+
interface ParsedWorktree extends Omit<GitWorktree, "dirty" | "primary"> {
|
|
15
|
+
}
|
|
16
|
+
export interface CreateWorktreeOptions {
|
|
17
|
+
branch: string;
|
|
18
|
+
createBranch: boolean;
|
|
19
|
+
baseRef?: string;
|
|
20
|
+
destination?: string;
|
|
21
|
+
projectName?: string;
|
|
22
|
+
}
|
|
23
|
+
export declare function defaultWorktreesDir(homeDir?: string): string;
|
|
24
|
+
export declare function parseGitWorktreePorcelain(output: string): ParsedWorktree[];
|
|
25
|
+
export declare class GitWorktreeManager {
|
|
26
|
+
private readonly repositoryPath;
|
|
27
|
+
private readonly managedRoot;
|
|
28
|
+
constructor(repositoryPath: string, managedRoot?: string);
|
|
29
|
+
list(): Promise<GitWorktree[]>;
|
|
30
|
+
create(options: CreateWorktreeOptions): Promise<GitWorktree>;
|
|
31
|
+
remove(path: string): Promise<void>;
|
|
32
|
+
prune(): Promise<void>;
|
|
33
|
+
}
|
|
34
|
+
export {};
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { mkdir, realpath } from "node:fs/promises";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
import { basename, join, resolve } from "node:path";
|
|
5
|
+
import { promisify } from "node:util";
|
|
6
|
+
const execFileAsync = promisify(execFile);
|
|
7
|
+
const HEADS_PREFIX = "refs/heads/";
|
|
8
|
+
const UNSAFE_PATH_SEGMENT = /[^a-zA-Z0-9._-]+/g;
|
|
9
|
+
export function defaultWorktreesDir(homeDir = homedir()) {
|
|
10
|
+
const override = process.env.NOMOREIDE_WORKTREES_DIR?.trim();
|
|
11
|
+
return resolve(override || join(homeDir, ".nomoreide", "worktrees"));
|
|
12
|
+
}
|
|
13
|
+
export function parseGitWorktreePorcelain(output) {
|
|
14
|
+
return output
|
|
15
|
+
.split("\0\0")
|
|
16
|
+
.map((record) => record.split("\0").filter(Boolean))
|
|
17
|
+
.filter((fields) => fields.some((field) => field.startsWith("worktree ")))
|
|
18
|
+
.map((fields) => {
|
|
19
|
+
const value = (key) => {
|
|
20
|
+
const field = fields.find((item) => item === key || item.startsWith(`${key} `));
|
|
21
|
+
return field?.slice(key.length).trim() || undefined;
|
|
22
|
+
};
|
|
23
|
+
const branchRef = value("branch");
|
|
24
|
+
return {
|
|
25
|
+
path: value("worktree") ?? "",
|
|
26
|
+
head: value("HEAD") ?? "",
|
|
27
|
+
branch: branchRef?.startsWith(HEADS_PREFIX)
|
|
28
|
+
? branchRef.slice(HEADS_PREFIX.length)
|
|
29
|
+
: branchRef,
|
|
30
|
+
bare: fields.includes("bare"),
|
|
31
|
+
detached: fields.includes("detached"),
|
|
32
|
+
locked: fields.some((field) => field === "locked" || field.startsWith("locked ")),
|
|
33
|
+
lockedReason: value("locked"),
|
|
34
|
+
prunable: fields.some((field) => field === "prunable" || field.startsWith("prunable ")),
|
|
35
|
+
prunableReason: value("prunable"),
|
|
36
|
+
};
|
|
37
|
+
})
|
|
38
|
+
.filter((worktree) => worktree.path);
|
|
39
|
+
}
|
|
40
|
+
export class GitWorktreeManager {
|
|
41
|
+
repositoryPath;
|
|
42
|
+
managedRoot;
|
|
43
|
+
constructor(repositoryPath, managedRoot = defaultWorktreesDir()) {
|
|
44
|
+
this.repositoryPath = repositoryPath;
|
|
45
|
+
this.managedRoot = managedRoot;
|
|
46
|
+
}
|
|
47
|
+
async list() {
|
|
48
|
+
const { stdout } = await execFileAsync("git", ["worktree", "list", "--porcelain", "-z"], { cwd: this.repositoryPath });
|
|
49
|
+
const parsed = parseGitWorktreePorcelain(stdout);
|
|
50
|
+
return Promise.all(parsed.map(async (worktree, index) => ({
|
|
51
|
+
...worktree,
|
|
52
|
+
primary: index === 0,
|
|
53
|
+
dirty: worktree.bare ? false : await isDirty(worktree.path),
|
|
54
|
+
})));
|
|
55
|
+
}
|
|
56
|
+
async create(options) {
|
|
57
|
+
const branch = requireBranchName(options.branch);
|
|
58
|
+
const project = safeSegment(options.projectName || basename(this.repositoryPath));
|
|
59
|
+
const destination = options.destination ??
|
|
60
|
+
join(this.managedRoot, project, safeSegment(branch));
|
|
61
|
+
await mkdir(resolve(destination, ".."), { recursive: true });
|
|
62
|
+
const args = ["worktree", "add"];
|
|
63
|
+
if (options.createBranch) {
|
|
64
|
+
args.push("-b", branch, destination, options.baseRef?.trim() || "HEAD");
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
args.push(destination, branch);
|
|
68
|
+
}
|
|
69
|
+
await execFileAsync("git", args, { cwd: this.repositoryPath });
|
|
70
|
+
const canonicalDestination = await canonicalPath(destination);
|
|
71
|
+
const worktrees = await this.list();
|
|
72
|
+
const canonicalPaths = await Promise.all(worktrees.map((worktree) => canonicalPath(worktree.path)));
|
|
73
|
+
const created = worktrees.find((_worktree, index) => canonicalPaths[index] === canonicalDestination);
|
|
74
|
+
if (!created) {
|
|
75
|
+
throw new Error(`Git created the worktree but it could not be found: ${destination}`);
|
|
76
|
+
}
|
|
77
|
+
return created;
|
|
78
|
+
}
|
|
79
|
+
async remove(path) {
|
|
80
|
+
const target = await canonicalPath(path);
|
|
81
|
+
const worktrees = await this.list();
|
|
82
|
+
const canonicalPaths = await Promise.all(worktrees.map((worktree) => canonicalPath(worktree.path)));
|
|
83
|
+
const worktree = worktrees.find((_candidate, index) => canonicalPaths[index] === target);
|
|
84
|
+
if (!worktree)
|
|
85
|
+
throw new Error("Unknown worktree.");
|
|
86
|
+
if (worktree.primary)
|
|
87
|
+
throw new Error("The primary worktree cannot be removed.");
|
|
88
|
+
if (worktree.locked)
|
|
89
|
+
throw new Error("Unlock this worktree before removing it.");
|
|
90
|
+
if (worktree.dirty) {
|
|
91
|
+
throw new Error("Commit, stash, or discard this worktree's changes before removing it.");
|
|
92
|
+
}
|
|
93
|
+
await execFileAsync("git", ["worktree", "remove", worktree.path], {
|
|
94
|
+
cwd: this.repositoryPath,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
async prune() {
|
|
98
|
+
await execFileAsync("git", ["worktree", "prune"], {
|
|
99
|
+
cwd: this.repositoryPath,
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
function requireBranchName(value) {
|
|
104
|
+
const branch = value.trim();
|
|
105
|
+
if (!branch || branch.startsWith("-") || branch.includes("\0")) {
|
|
106
|
+
throw new Error("A valid branch name is required.");
|
|
107
|
+
}
|
|
108
|
+
return branch;
|
|
109
|
+
}
|
|
110
|
+
function safeSegment(value) {
|
|
111
|
+
const result = value
|
|
112
|
+
.trim()
|
|
113
|
+
.replace(UNSAFE_PATH_SEGMENT, "-")
|
|
114
|
+
.replace(/^-+|-+$/g, "");
|
|
115
|
+
if (!result || result === "." || result === "..") {
|
|
116
|
+
throw new Error("Could not derive a safe worktree folder name.");
|
|
117
|
+
}
|
|
118
|
+
return result;
|
|
119
|
+
}
|
|
120
|
+
async function isDirty(path) {
|
|
121
|
+
try {
|
|
122
|
+
const { stdout } = await execFileAsync("git", ["status", "--porcelain=v1", "--untracked-files=all"], { cwd: path });
|
|
123
|
+
return stdout.length > 0;
|
|
124
|
+
}
|
|
125
|
+
catch {
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
async function canonicalPath(path) {
|
|
130
|
+
return realpath(path).catch(() => resolve(path));
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=git-worktrees.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-worktrees.js","sourceRoot":"","sources":["../../src/core/git-worktrees.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { ProcessManager } from "./process-manager.js";
|
|
2
|
+
import { type DockerContainerStats } from "./docker-stats.js";
|
|
2
3
|
import { HostMetricsCollector, type HostMetricSample } from "./host-metrics.js";
|
|
3
4
|
import { type ProcessTreeSummary } from "./process-tree.js";
|
|
5
|
+
import { type SystemProcess } from "./system-processes.js";
|
|
4
6
|
export interface MetricSample {
|
|
5
7
|
t: number;
|
|
6
8
|
cpu: number;
|
|
@@ -18,7 +20,9 @@ export interface ServiceActivityMetric {
|
|
|
18
20
|
sampledAt: number;
|
|
19
21
|
cpuPercent: number;
|
|
20
22
|
rssMb: number;
|
|
21
|
-
processCount
|
|
23
|
+
processCount?: number;
|
|
24
|
+
memoryPercent?: number;
|
|
25
|
+
source: "local" | "docker";
|
|
22
26
|
}
|
|
23
27
|
export interface ActivityMetrics {
|
|
24
28
|
sampleIntervalMs: number;
|
|
@@ -27,6 +31,7 @@ export interface ActivityMetrics {
|
|
|
27
31
|
samples: HostMetricSample[];
|
|
28
32
|
};
|
|
29
33
|
services: Record<string, ServiceActivityMetric>;
|
|
34
|
+
systemProcesses: SystemProcess[];
|
|
30
35
|
}
|
|
31
36
|
export interface MetricsStoreOptions {
|
|
32
37
|
manager: ProcessManager;
|
|
@@ -37,6 +42,8 @@ export interface MetricsStoreOptions {
|
|
|
37
42
|
cwd?: string;
|
|
38
43
|
hostCollector?: Pick<HostMetricsCollector, "sample">;
|
|
39
44
|
processTreeReader?: (rootPid: number) => Promise<ProcessTreeSummary>;
|
|
45
|
+
systemProcessReader?: () => Promise<SystemProcess[]>;
|
|
46
|
+
dockerStatsReader?: () => Promise<DockerContainerStats[]>;
|
|
40
47
|
now?: () => number;
|
|
41
48
|
}
|
|
42
49
|
/**
|
|
@@ -50,9 +57,12 @@ export declare class MetricsStore {
|
|
|
50
57
|
private readonly capacity;
|
|
51
58
|
private readonly hostCollector;
|
|
52
59
|
private readonly processTreeReader;
|
|
60
|
+
private readonly systemProcessReader;
|
|
61
|
+
private readonly dockerStatsReader;
|
|
53
62
|
private readonly now;
|
|
54
63
|
private readonly buffers;
|
|
55
64
|
private readonly hostSamples;
|
|
65
|
+
private systemProcesses;
|
|
56
66
|
private timer?;
|
|
57
67
|
private sampling;
|
|
58
68
|
constructor(options: MetricsStoreOptions);
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { findStatsFor, indexStatsById, listDockerStats, parseDockerMemoryUsageMb, } from "./docker-stats.js";
|
|
1
2
|
import { HostMetricsCollector, } from "./host-metrics.js";
|
|
2
3
|
import { readProcessTree, } from "./process-tree.js";
|
|
4
|
+
import { classifySystemProcesses, readSystemProcesses, } from "./system-processes.js";
|
|
3
5
|
/**
|
|
4
6
|
* In-memory CPU/RSS time series for managed services. Polls process trees on a
|
|
5
7
|
* fixed cadence; PIDs that disappear are kept in the buffer so the chart can
|
|
@@ -11,9 +13,12 @@ export class MetricsStore {
|
|
|
11
13
|
capacity;
|
|
12
14
|
hostCollector;
|
|
13
15
|
processTreeReader;
|
|
16
|
+
systemProcessReader;
|
|
17
|
+
dockerStatsReader;
|
|
14
18
|
now;
|
|
15
19
|
buffers = new Map();
|
|
16
20
|
hostSamples = [];
|
|
21
|
+
systemProcesses = [];
|
|
17
22
|
timer;
|
|
18
23
|
sampling = false;
|
|
19
24
|
constructor(options) {
|
|
@@ -23,6 +28,8 @@ export class MetricsStore {
|
|
|
23
28
|
this.hostCollector =
|
|
24
29
|
options.hostCollector ?? new HostMetricsCollector(options.cwd ?? process.cwd());
|
|
25
30
|
this.processTreeReader = options.processTreeReader ?? readProcessTree;
|
|
31
|
+
this.systemProcessReader = options.systemProcessReader ?? readSystemProcesses;
|
|
32
|
+
this.dockerStatsReader = options.dockerStatsReader ?? listDockerStats;
|
|
26
33
|
this.now = options.now ?? Date.now;
|
|
27
34
|
}
|
|
28
35
|
start() {
|
|
@@ -63,9 +70,11 @@ export class MetricsStore {
|
|
|
63
70
|
service: name,
|
|
64
71
|
startedAt: buffer.startedAt,
|
|
65
72
|
sampledAt: buffer.latest.sampledAt,
|
|
66
|
-
cpuPercent: buffer.latest.
|
|
67
|
-
rssMb: buffer.latest.
|
|
68
|
-
processCount: buffer.latest.
|
|
73
|
+
cpuPercent: buffer.latest.cpuPercent,
|
|
74
|
+
rssMb: buffer.latest.rssMb,
|
|
75
|
+
processCount: buffer.latest.processCount,
|
|
76
|
+
memoryPercent: buffer.latest.memoryPercent,
|
|
77
|
+
source: buffer.latest.source,
|
|
69
78
|
};
|
|
70
79
|
}
|
|
71
80
|
return {
|
|
@@ -75,6 +84,9 @@ export class MetricsStore {
|
|
|
75
84
|
samples: this.hostSamples.map(cloneHostSample),
|
|
76
85
|
},
|
|
77
86
|
services,
|
|
87
|
+
systemProcesses: classifySystemProcesses(this.systemProcesses, Object.values(statuses)
|
|
88
|
+
.filter((status) => status.state === "running" && status.pid)
|
|
89
|
+
.map((status) => ({ pid: status.pid, service: status.name }))),
|
|
78
90
|
};
|
|
79
91
|
}
|
|
80
92
|
async sampleOnce() {
|
|
@@ -85,9 +97,20 @@ export class MetricsStore {
|
|
|
85
97
|
const { services } = this.manager.status();
|
|
86
98
|
const now = this.now();
|
|
87
99
|
const hostSample = this.hostCollector.sample(now).catch(() => undefined);
|
|
100
|
+
const systemProcesses = this.systemProcessReader().catch(() => undefined);
|
|
101
|
+
const dockerServices = Object.values(services).filter((status) => status.state === "running" &&
|
|
102
|
+
status.kind === "docker-compose" &&
|
|
103
|
+
status.containerId);
|
|
104
|
+
const dockerStats = dockerServices.length > 0
|
|
105
|
+
? this.dockerStatsReader().catch(() => undefined)
|
|
106
|
+
: Promise.resolve(undefined);
|
|
88
107
|
await Promise.all(Object.values(services).map(async (status) => {
|
|
89
|
-
if (status.state !== "running" ||
|
|
108
|
+
if (status.state !== "running" ||
|
|
109
|
+
!status.pid ||
|
|
110
|
+
status.kind === "docker-compose" ||
|
|
111
|
+
status.kind === "ssh") {
|
|
90
112
|
return;
|
|
113
|
+
}
|
|
91
114
|
let buffer = this.buffers.get(status.name);
|
|
92
115
|
// New run (or first sample) → reset the series so the chart starts at startedAt.
|
|
93
116
|
if (!buffer || buffer.startedAt !== status.startedAt) {
|
|
@@ -97,7 +120,13 @@ export class MetricsStore {
|
|
|
97
120
|
try {
|
|
98
121
|
const tree = await this.processTreeReader(status.pid);
|
|
99
122
|
buffer.samples.push({ t: now, cpu: tree.cpuPercent, rss: tree.rssMb });
|
|
100
|
-
buffer.latest = {
|
|
123
|
+
buffer.latest = {
|
|
124
|
+
sampledAt: now,
|
|
125
|
+
cpuPercent: tree.cpuPercent,
|
|
126
|
+
rssMb: tree.rssMb,
|
|
127
|
+
processCount: tree.processCount,
|
|
128
|
+
source: "local",
|
|
129
|
+
};
|
|
101
130
|
if (buffer.samples.length > this.capacity) {
|
|
102
131
|
buffer.samples.splice(0, buffer.samples.length - this.capacity);
|
|
103
132
|
}
|
|
@@ -106,6 +135,32 @@ export class MetricsStore {
|
|
|
106
135
|
// ps may briefly fail right after spawn / during exit — skip this tick.
|
|
107
136
|
}
|
|
108
137
|
}));
|
|
138
|
+
const nextDockerStats = await dockerStats;
|
|
139
|
+
if (nextDockerStats) {
|
|
140
|
+
const statsById = indexStatsById(nextDockerStats);
|
|
141
|
+
for (const status of dockerServices) {
|
|
142
|
+
const stats = findStatsFor(statsById, status.containerId);
|
|
143
|
+
const rssMb = stats ? parseDockerMemoryUsageMb(stats.memoryUsage) : null;
|
|
144
|
+
if (!stats || stats.cpuPercent === null || rssMb === null)
|
|
145
|
+
continue;
|
|
146
|
+
let buffer = this.buffers.get(status.name);
|
|
147
|
+
if (!buffer || buffer.startedAt !== status.startedAt) {
|
|
148
|
+
buffer = { startedAt: status.startedAt, samples: [] };
|
|
149
|
+
this.buffers.set(status.name, buffer);
|
|
150
|
+
}
|
|
151
|
+
buffer.samples.push({ t: now, cpu: stats.cpuPercent, rss: rssMb });
|
|
152
|
+
buffer.latest = {
|
|
153
|
+
sampledAt: now,
|
|
154
|
+
cpuPercent: stats.cpuPercent,
|
|
155
|
+
rssMb,
|
|
156
|
+
memoryPercent: stats.memoryPercent ?? undefined,
|
|
157
|
+
source: "docker",
|
|
158
|
+
};
|
|
159
|
+
if (buffer.samples.length > this.capacity) {
|
|
160
|
+
buffer.samples.splice(0, buffer.samples.length - this.capacity);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
109
164
|
const nextHostSample = await hostSample;
|
|
110
165
|
if (nextHostSample) {
|
|
111
166
|
this.hostSamples.push(nextHostSample);
|
|
@@ -113,6 +168,9 @@ export class MetricsStore {
|
|
|
113
168
|
this.hostSamples.splice(0, this.hostSamples.length - this.capacity);
|
|
114
169
|
}
|
|
115
170
|
}
|
|
171
|
+
const nextSystemProcesses = await systemProcesses;
|
|
172
|
+
if (nextSystemProcesses)
|
|
173
|
+
this.systemProcesses = nextSystemProcesses;
|
|
116
174
|
}
|
|
117
175
|
finally {
|
|
118
176
|
this.sampling = false;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metrics-store.js","sourceRoot":"","sources":["../../src/core/metrics-store.ts"],"names":[],"mappings":"AACA,OAAO,EACL,oBAAoB,GAErB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,eAAe,GAEhB,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"metrics-store.js","sourceRoot":"","sources":["../../src/core/metrics-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
export interface RemoteSkillResult {
|
|
3
|
+
id: string;
|
|
4
|
+
name: string;
|
|
5
|
+
source: string;
|
|
6
|
+
useSource: string;
|
|
7
|
+
installs: number;
|
|
8
|
+
url: string;
|
|
9
|
+
}
|
|
10
|
+
export interface OneTimeSkillSelection {
|
|
11
|
+
name: string;
|
|
12
|
+
source: string;
|
|
13
|
+
}
|
|
14
|
+
export declare class OneTimeSkillError extends Error {
|
|
15
|
+
readonly code: "invalid_query" | "invalid_response" | "invalid_source" | "network" | "runtime_missing" | "skill_unavailable" | "timeout" | "too_large";
|
|
16
|
+
constructor(code: "invalid_query" | "invalid_response" | "invalid_source" | "network" | "runtime_missing" | "skill_unavailable" | "timeout" | "too_large", message: string);
|
|
17
|
+
}
|
|
18
|
+
export declare function searchRemoteSkills(rawQuery: string, options?: {
|
|
19
|
+
fetch?: typeof fetch;
|
|
20
|
+
signal?: AbortSignal;
|
|
21
|
+
}): Promise<RemoteSkillResult[]>;
|
|
22
|
+
export declare function validateOneTimeSkill(selection: OneTimeSkillSelection): void;
|
|
23
|
+
export declare function resolveOneTimeSkill(selection: OneTimeSkillSelection, options?: {
|
|
24
|
+
execFile?: typeof execFile;
|
|
25
|
+
platform?: NodeJS.Platform;
|
|
26
|
+
}): Promise<string>;
|
|
27
|
+
export declare function composeOneTimeSkillPrompt(skillPrompt: string, userPrompt: string): string;
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
const SKILLS_SEARCH_URL = "https://skills.sh/api/search";
|
|
3
|
+
const SKILLS_CLI_VERSION = "1.5.20";
|
|
4
|
+
const SEARCH_LIMIT = 6;
|
|
5
|
+
const SEARCH_TIMEOUT_MS = 8_000;
|
|
6
|
+
const USE_TIMEOUT_MS = 60_000;
|
|
7
|
+
const MAX_SEARCH_RESPONSE_BYTES = 256 * 1024;
|
|
8
|
+
const MAX_SKILL_PROMPT_BYTES = 256 * 1024;
|
|
9
|
+
const MAX_COMBINED_PROMPT_BYTES = 512 * 1024;
|
|
10
|
+
const GITHUB_SOURCE = /^[A-Za-z0-9](?:[A-Za-z0-9._-]{0,99})\/[A-Za-z0-9](?:[A-Za-z0-9._-]{0,99})$/;
|
|
11
|
+
const SKILL_SELECTOR = /^[A-Za-z0-9](?:[A-Za-z0-9._:-]{0,199})$/;
|
|
12
|
+
export class OneTimeSkillError extends Error {
|
|
13
|
+
code;
|
|
14
|
+
constructor(code, message) {
|
|
15
|
+
super(message);
|
|
16
|
+
this.code = code;
|
|
17
|
+
this.name = "OneTimeSkillError";
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function selectorFor(id, source) {
|
|
21
|
+
const prefix = `${source}/`;
|
|
22
|
+
if (!id.startsWith(prefix))
|
|
23
|
+
return null;
|
|
24
|
+
const selector = id.slice(prefix.length);
|
|
25
|
+
return SKILL_SELECTOR.test(selector) ? selector : null;
|
|
26
|
+
}
|
|
27
|
+
function normalizeSearchEntry(value) {
|
|
28
|
+
if (!value || typeof value !== "object")
|
|
29
|
+
return null;
|
|
30
|
+
const entry = value;
|
|
31
|
+
if (typeof entry.id !== "string" ||
|
|
32
|
+
typeof entry.name !== "string" ||
|
|
33
|
+
typeof entry.source !== "string" ||
|
|
34
|
+
!GITHUB_SOURCE.test(entry.source)) {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
const selector = selectorFor(entry.id, entry.source);
|
|
38
|
+
if (!selector)
|
|
39
|
+
return null;
|
|
40
|
+
return {
|
|
41
|
+
id: entry.id,
|
|
42
|
+
name: entry.name.slice(0, 200),
|
|
43
|
+
source: entry.source,
|
|
44
|
+
useSource: `${entry.source}@${selector}`,
|
|
45
|
+
installs: typeof entry.installs === "number" && Number.isFinite(entry.installs)
|
|
46
|
+
? Math.max(0, Math.trunc(entry.installs))
|
|
47
|
+
: 0,
|
|
48
|
+
url: `https://skills.sh/${entry.id}`,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
async function readResponseText(response, maximumBytes) {
|
|
52
|
+
if (!response.body)
|
|
53
|
+
return "";
|
|
54
|
+
const reader = response.body.getReader();
|
|
55
|
+
const chunks = [];
|
|
56
|
+
let total = 0;
|
|
57
|
+
try {
|
|
58
|
+
while (true) {
|
|
59
|
+
const { done, value } = await reader.read();
|
|
60
|
+
if (done)
|
|
61
|
+
break;
|
|
62
|
+
total += value.byteLength;
|
|
63
|
+
if (total > maximumBytes) {
|
|
64
|
+
await reader.cancel();
|
|
65
|
+
throw new OneTimeSkillError("invalid_response", "skills.sh returned too much search data.");
|
|
66
|
+
}
|
|
67
|
+
chunks.push(value);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
finally {
|
|
71
|
+
reader.releaseLock();
|
|
72
|
+
}
|
|
73
|
+
return Buffer.concat(chunks.map((chunk) => Buffer.from(chunk)), total).toString("utf8");
|
|
74
|
+
}
|
|
75
|
+
export async function searchRemoteSkills(rawQuery, options = {}) {
|
|
76
|
+
const query = rawQuery.trim();
|
|
77
|
+
if (query.length < 2 || query.length > 100) {
|
|
78
|
+
throw new OneTimeSkillError("invalid_query", "Skill search must be 2–100 characters.");
|
|
79
|
+
}
|
|
80
|
+
const timeout = AbortSignal.timeout(SEARCH_TIMEOUT_MS);
|
|
81
|
+
const signal = options.signal
|
|
82
|
+
? AbortSignal.any([options.signal, timeout])
|
|
83
|
+
: timeout;
|
|
84
|
+
const url = new URL(SKILLS_SEARCH_URL);
|
|
85
|
+
url.searchParams.set("q", query);
|
|
86
|
+
url.searchParams.set("limit", String(SEARCH_LIMIT));
|
|
87
|
+
let response;
|
|
88
|
+
try {
|
|
89
|
+
response = await (options.fetch ?? fetch)(url, { signal });
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
if (signal.aborted) {
|
|
93
|
+
throw new OneTimeSkillError("timeout", "Skill search timed out.");
|
|
94
|
+
}
|
|
95
|
+
throw new OneTimeSkillError("network", `Could not search skills.sh: ${error instanceof Error ? error.message : String(error)}`);
|
|
96
|
+
}
|
|
97
|
+
if (!response.ok) {
|
|
98
|
+
throw new OneTimeSkillError("network", `skills.sh search failed with HTTP ${response.status}.`);
|
|
99
|
+
}
|
|
100
|
+
const declaredLength = Number(response.headers.get("content-length"));
|
|
101
|
+
if (Number.isFinite(declaredLength) &&
|
|
102
|
+
declaredLength > MAX_SEARCH_RESPONSE_BYTES) {
|
|
103
|
+
throw new OneTimeSkillError("invalid_response", "skills.sh returned too much search data.");
|
|
104
|
+
}
|
|
105
|
+
let payload;
|
|
106
|
+
try {
|
|
107
|
+
const text = await readResponseText(response, MAX_SEARCH_RESPONSE_BYTES);
|
|
108
|
+
payload = JSON.parse(text);
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
if (error instanceof OneTimeSkillError)
|
|
112
|
+
throw error;
|
|
113
|
+
throw new OneTimeSkillError("invalid_response", "skills.sh returned invalid JSON.");
|
|
114
|
+
}
|
|
115
|
+
if (!Array.isArray(payload.skills)) {
|
|
116
|
+
throw new OneTimeSkillError("invalid_response", "skills.sh returned an invalid search result.");
|
|
117
|
+
}
|
|
118
|
+
return payload.skills
|
|
119
|
+
.map(normalizeSearchEntry)
|
|
120
|
+
.filter((item) => item !== null)
|
|
121
|
+
.slice(0, SEARCH_LIMIT);
|
|
122
|
+
}
|
|
123
|
+
export function validateOneTimeSkill(selection) {
|
|
124
|
+
const at = selection.source.lastIndexOf("@");
|
|
125
|
+
const repository = selection.source.slice(0, at);
|
|
126
|
+
const selector = selection.source.slice(at + 1);
|
|
127
|
+
if (at <= 0 ||
|
|
128
|
+
!GITHUB_SOURCE.test(repository) ||
|
|
129
|
+
!SKILL_SELECTOR.test(selector) ||
|
|
130
|
+
selection.name.trim().length === 0 ||
|
|
131
|
+
selection.name.length > 200) {
|
|
132
|
+
throw new OneTimeSkillError("invalid_source", "The selected skill source is invalid.");
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
export function resolveOneTimeSkill(selection, options = {}) {
|
|
136
|
+
validateOneTimeSkill(selection);
|
|
137
|
+
const executable = (options.platform ?? process.platform) === "win32" ? "npx.cmd" : "npx";
|
|
138
|
+
const run = options.execFile ?? execFile;
|
|
139
|
+
return new Promise((resolve, reject) => {
|
|
140
|
+
run(executable, ["--yes", `skills@${SKILLS_CLI_VERSION}`, "use", selection.source], {
|
|
141
|
+
env: {
|
|
142
|
+
...process.env,
|
|
143
|
+
CI: "1",
|
|
144
|
+
NO_COLOR: "1",
|
|
145
|
+
npm_config_yes: "true",
|
|
146
|
+
},
|
|
147
|
+
maxBuffer: MAX_SKILL_PROMPT_BYTES,
|
|
148
|
+
timeout: USE_TIMEOUT_MS,
|
|
149
|
+
windowsHide: true,
|
|
150
|
+
}, (error, stdout, stderr) => {
|
|
151
|
+
if (!error) {
|
|
152
|
+
const prompt = stdout.toString();
|
|
153
|
+
if (!prompt.trim()) {
|
|
154
|
+
reject(new OneTimeSkillError("skill_unavailable", "The skills CLI returned an empty skill."));
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
resolve(prompt);
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
const processError = error;
|
|
161
|
+
if (processError.code === "ENOENT") {
|
|
162
|
+
reject(new OneTimeSkillError("runtime_missing", "Node.js and npm are required to use a temporary skill."));
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
if (processError.killed || processError.code === "ETIMEDOUT") {
|
|
166
|
+
reject(new OneTimeSkillError("timeout", "Loading the temporary skill timed out."));
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
if (processError.code === "ERR_CHILD_PROCESS_STDIO_MAXBUFFER") {
|
|
170
|
+
reject(new OneTimeSkillError("too_large", "The temporary skill is too large to use."));
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
const detail = stderr.toString().trim();
|
|
174
|
+
reject(new OneTimeSkillError("skill_unavailable", detail || "The temporary skill could not be loaded."));
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
export function composeOneTimeSkillPrompt(skillPrompt, userPrompt) {
|
|
179
|
+
const combined = `${skillPrompt.trimEnd()}\n\nUser's request:\n${userPrompt}`;
|
|
180
|
+
if (Buffer.byteLength(combined, "utf8") > MAX_COMBINED_PROMPT_BYTES) {
|
|
181
|
+
throw new OneTimeSkillError("too_large", "The temporary skill and task are too large to send together.");
|
|
182
|
+
}
|
|
183
|
+
return combined;
|
|
184
|
+
}
|
|
185
|
+
//# sourceMappingURL=one-time-skills.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"one-time-skills.js","sourceRoot":"","sources":["../../src/core/one-time-skills.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export type ProcessProtection = "managed" | "permission" | "system" | "this-app";
|
|
2
|
+
export interface SystemProcess {
|
|
3
|
+
pid: number;
|
|
4
|
+
ppid: number;
|
|
5
|
+
uid: number;
|
|
6
|
+
user: string;
|
|
7
|
+
cpuPercent: number;
|
|
8
|
+
rssMb: number;
|
|
9
|
+
command: string;
|
|
10
|
+
managedService?: string;
|
|
11
|
+
canTerminate: boolean;
|
|
12
|
+
protection?: ProcessProtection;
|
|
13
|
+
}
|
|
14
|
+
export interface ManagedProcessRoot {
|
|
15
|
+
pid: number;
|
|
16
|
+
service: string;
|
|
17
|
+
}
|
|
18
|
+
export declare function parseSystemProcesses(raw: string): SystemProcess[];
|
|
19
|
+
export declare function readSystemProcesses(): Promise<SystemProcess[]>;
|
|
20
|
+
export declare function classifySystemProcesses(rows: SystemProcess[], managedRoots: ManagedProcessRoot[], options?: {
|
|
21
|
+
currentPid?: number;
|
|
22
|
+
currentUid?: number;
|
|
23
|
+
}): SystemProcess[];
|
|
24
|
+
export declare function terminateSystemProcess(pid: number, expectedCommand: string, managedRoots: ManagedProcessRoot[], options?: {
|
|
25
|
+
currentPid?: number;
|
|
26
|
+
currentUid?: number;
|
|
27
|
+
read?: () => Promise<SystemProcess[]>;
|
|
28
|
+
signal?: (pid: number) => void;
|
|
29
|
+
}): Promise<void>;
|