@holmes-lab/holmes-kit 0.10.1 → 0.12.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 +58 -1
- package/README.md +2 -0
- package/dist/.build-id +1 -1
- package/dist/holmes/cli/approve.js +2 -1
- package/dist/holmes/cli/doctor.js +6 -3
- package/dist/holmes/cli/index.js +49 -0
- package/dist/holmes/cli/upgrade.d.ts +14 -0
- package/dist/holmes/cli/upgrade.js +177 -0
- package/dist/holmes/governance/approval-queue.js +3 -2
- package/dist/holmes/hooks/session-start.js +45 -0
- package/dist/holmes/hooks/stop.js +2 -1
- package/dist/holmes/mcp/elicit-approval.js +4 -3
- package/dist/holmes/mcp/handlers.d.ts +17 -1
- package/dist/holmes/mcp/handlers.js +34 -0
- package/dist/holmes/mcp/tool-schemas.js +10 -0
- package/dist/holmes/project/npx-bin.d.ts +10 -0
- package/dist/holmes/project/npx-bin.js +16 -0
- package/dist/holmes/server/cfg-view.d.ts +45 -0
- package/dist/holmes/server/cfg-view.js +57 -0
- package/dist/holmes/server/dashboard-launcher.d.ts +40 -0
- package/dist/holmes/server/dashboard-launcher.js +54 -0
- package/dist/holmes/server/dashboard.js +206 -152
- package/dist/holmes/server/rtm-matrix.d.ts +47 -0
- package/dist/holmes/server/rtm-matrix.js +83 -0
- package/dist/holmes/update/update-notice.js +4 -2
- package/dist/holmes/update/upgrade-plan.d.ts +43 -0
- package/dist/holmes/update/upgrade-plan.js +45 -0
- package/dist/holmes/update/workspaces.d.ts +35 -0
- package/dist/holmes/update/workspaces.js +109 -0
- package/package.json +1 -1
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.NO_AUTO_REPIN_ENV = void 0;
|
|
4
|
+
exports.planUpgrade = planUpgrade;
|
|
5
|
+
exports.repinDecision = repinDecision;
|
|
6
|
+
// @implements A-SPEC-543.2
|
|
7
|
+
const update_notice_1 = require("./update-notice");
|
|
8
|
+
/**
|
|
9
|
+
* @implements A-SPEC-543.2
|
|
10
|
+
* Pure: decide whether an upgrade runs and what it touches. Unknown latest is a noop (silence is not
|
|
11
|
+
* an install), and so is an equal or OLDER latest — upgrade never plans a downgrade. A 'run' plan
|
|
12
|
+
* carries the registry's workspaces verbatim as the re-pin list; an empty list is still a valid run
|
|
13
|
+
* (install-only, first machine).
|
|
14
|
+
*/
|
|
15
|
+
function planUpgrade(a) {
|
|
16
|
+
if (a.latest === null) {
|
|
17
|
+
return { kind: 'noop', reason: 'latest version unknown (registry unreachable and no cache) — nothing to plan' };
|
|
18
|
+
}
|
|
19
|
+
if ((0, update_notice_1.compareSemver)(a.latest, a.current) <= 0) {
|
|
20
|
+
return { kind: 'noop', reason: `already up to date (current ${a.current}, latest ${a.latest})` };
|
|
21
|
+
}
|
|
22
|
+
return { kind: 'run', current: a.current, latest: a.latest, installMode: a.installMode, repins: a.registry.workspaces };
|
|
23
|
+
}
|
|
24
|
+
/** The env switch that turns SessionStart's forward self-heal re-pin OFF. */
|
|
25
|
+
exports.NO_AUTO_REPIN_ENV = 'HOLMES_NO_AUTO_REPIN';
|
|
26
|
+
/**
|
|
27
|
+
* @implements A-SPEC-543.3
|
|
28
|
+
* Pure: should a session auto re-pin this workspace's derived artifacts? Only when the pin is a real
|
|
29
|
+
* version, the installed package is strictly NEWER (forward-only — never a downgrade or a match), and
|
|
30
|
+
* the operator has not opted out. The install was the user's explicit choice; this completes it at
|
|
31
|
+
* the workspace level. A decision always says why.
|
|
32
|
+
*/
|
|
33
|
+
function repinDecision(a) {
|
|
34
|
+
const optOut = a.env[exports.NO_AUTO_REPIN_ENV];
|
|
35
|
+
if (typeof optOut === 'string' && optOut !== '') {
|
|
36
|
+
return { repin: false, reason: `${exports.NO_AUTO_REPIN_ENV} set — auto re-pin disabled` };
|
|
37
|
+
}
|
|
38
|
+
if (a.pinned === null) {
|
|
39
|
+
return { repin: false, reason: 'workspace pin unreadable — no re-pin on an unknown pin' };
|
|
40
|
+
}
|
|
41
|
+
if ((0, update_notice_1.compareSemver)(a.installed, a.pinned) > 0) {
|
|
42
|
+
return { repin: true, reason: `installed ${a.installed} is newer than pin ${a.pinned} — re-pin forward` };
|
|
43
|
+
}
|
|
44
|
+
return { repin: false, reason: `pin ${a.pinned} is up to date with installed ${a.installed} — no re-pin` };
|
|
45
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/** One wired workspace, as the registry answers "what is wired NOW" (not a history). */
|
|
2
|
+
export interface WorkspaceEntry {
|
|
3
|
+
target: string;
|
|
4
|
+
agents: string[];
|
|
5
|
+
version: string;
|
|
6
|
+
ts: string;
|
|
7
|
+
}
|
|
8
|
+
export interface Registry {
|
|
9
|
+
version: 1;
|
|
10
|
+
workspaces: WorkspaceEntry[];
|
|
11
|
+
}
|
|
12
|
+
export declare const EMPTY_REGISTRY: Registry;
|
|
13
|
+
/**
|
|
14
|
+
* @implements A-SPEC-543.1
|
|
15
|
+
* Parse the registry file's content. `null` (absent), broken JSON, or a wrong shape all yield the
|
|
16
|
+
* empty registry — best-effort by design: a broken registry restarts empty rather than ever breaking
|
|
17
|
+
* wiring (the recorder that feeds it is swallowed too).
|
|
18
|
+
*/
|
|
19
|
+
export declare function readRegistry(raw: string | null): Registry;
|
|
20
|
+
/**
|
|
21
|
+
* @implements A-SPEC-543.1
|
|
22
|
+
* Pure: replace the entry whose `target` matches (path-identity dedup — the registry answers what is
|
|
23
|
+
* wired NOW), append otherwise, preserve order, never mutate the inputs.
|
|
24
|
+
*/
|
|
25
|
+
export declare function mergeWorkspaceEntry(reg: Registry, entry: WorkspaceEntry): Registry;
|
|
26
|
+
/**
|
|
27
|
+
* @implements A-SPEC-543.1
|
|
28
|
+
* Thin best-effort recorder: read → merge → write `~/.holmes/workspaces.json`. Every failure is
|
|
29
|
+
* swallowed (returns false) — a registry problem must never fail the init that feeds it.
|
|
30
|
+
*/
|
|
31
|
+
export declare function recordWorkspace(home: string, entry: WorkspaceEntry, io?: {
|
|
32
|
+
read: (p: string) => string;
|
|
33
|
+
write: (p: string, c: string) => void;
|
|
34
|
+
mkdir: (p: string) => void;
|
|
35
|
+
}): boolean;
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.EMPTY_REGISTRY = void 0;
|
|
37
|
+
exports.readRegistry = readRegistry;
|
|
38
|
+
exports.mergeWorkspaceEntry = mergeWorkspaceEntry;
|
|
39
|
+
exports.recordWorkspace = recordWorkspace;
|
|
40
|
+
// @implements A-SPEC-543.1
|
|
41
|
+
const fs = __importStar(require("node:fs"));
|
|
42
|
+
const path = __importStar(require("node:path"));
|
|
43
|
+
exports.EMPTY_REGISTRY = { version: 1, workspaces: [] };
|
|
44
|
+
/**
|
|
45
|
+
* @implements A-SPEC-543.1
|
|
46
|
+
* Parse the registry file's content. `null` (absent), broken JSON, or a wrong shape all yield the
|
|
47
|
+
* empty registry — best-effort by design: a broken registry restarts empty rather than ever breaking
|
|
48
|
+
* wiring (the recorder that feeds it is swallowed too).
|
|
49
|
+
*/
|
|
50
|
+
function readRegistry(raw) {
|
|
51
|
+
if (raw === null)
|
|
52
|
+
return { version: 1, workspaces: [] };
|
|
53
|
+
try {
|
|
54
|
+
const parsed = JSON.parse(raw);
|
|
55
|
+
if (!Array.isArray(parsed?.workspaces))
|
|
56
|
+
return { version: 1, workspaces: [] };
|
|
57
|
+
const workspaces = parsed.workspaces.filter((w) => !!w && typeof w.target === 'string'
|
|
58
|
+
&& Array.isArray(w.agents)
|
|
59
|
+
&& typeof w.version === 'string'
|
|
60
|
+
&& typeof w.ts === 'string');
|
|
61
|
+
return { version: 1, workspaces };
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
return { version: 1, workspaces: [] };
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* @implements A-SPEC-543.1
|
|
69
|
+
* Pure: replace the entry whose `target` matches (path-identity dedup — the registry answers what is
|
|
70
|
+
* wired NOW), append otherwise, preserve order, never mutate the inputs.
|
|
71
|
+
*/
|
|
72
|
+
function mergeWorkspaceEntry(reg, entry) {
|
|
73
|
+
const replaced = reg.workspaces.some((w) => w.target === entry.target);
|
|
74
|
+
return {
|
|
75
|
+
version: 1,
|
|
76
|
+
workspaces: replaced
|
|
77
|
+
? reg.workspaces.map((w) => (w.target === entry.target ? entry : w))
|
|
78
|
+
: [...reg.workspaces, entry],
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* @implements A-SPEC-543.1
|
|
83
|
+
* Thin best-effort recorder: read → merge → write `~/.holmes/workspaces.json`. Every failure is
|
|
84
|
+
* swallowed (returns false) — a registry problem must never fail the init that feeds it.
|
|
85
|
+
*/
|
|
86
|
+
function recordWorkspace(home, entry, io = {
|
|
87
|
+
read: (p) => fs.readFileSync(p, 'utf8'),
|
|
88
|
+
write: (p, c) => fs.writeFileSync(p, c),
|
|
89
|
+
mkdir: (p) => { fs.mkdirSync(p, { recursive: true }); },
|
|
90
|
+
}) {
|
|
91
|
+
try {
|
|
92
|
+
const dir = path.join(home, '.holmes');
|
|
93
|
+
const file = path.join(dir, 'workspaces.json');
|
|
94
|
+
let raw = null;
|
|
95
|
+
try {
|
|
96
|
+
raw = io.read(file);
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
raw = null;
|
|
100
|
+
}
|
|
101
|
+
const merged = mergeWorkspaceEntry(readRegistry(raw), entry);
|
|
102
|
+
io.mkdir(dir);
|
|
103
|
+
io.write(file, `${JSON.stringify(merged, null, 2)}\n`);
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"//": "@implements A-SPEC-209",
|
|
3
3
|
"name": "@holmes-lab/holmes-kit",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.12.0",
|
|
5
5
|
"description": "Holmes-Kit — deterministic Agentic Software Engineering (ASE) harness with causal traceability (spec chain + D-CPG + RTM + phase guardrail)",
|
|
6
6
|
"main": "dist/holmes/mcp/server.js",
|
|
7
7
|
"types": "dist/holmes/mcp/server.d.ts",
|