harnery 0.6.0 → 0.7.1
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/README.md +16 -6
- package/dist/commander.d.ts +19 -0
- package/dist/commander.d.ts.map +1 -1
- package/dist/commander.js +2 -0
- package/dist/commands/agents.d.ts.map +1 -1
- package/dist/commands/agents.js +51 -4
- package/dist/commands/deinit.d.ts.map +1 -1
- package/dist/commands/deinit.js +4 -0
- package/dist/commands/devtools.d.ts +4 -0
- package/dist/commands/devtools.d.ts.map +1 -0
- package/dist/commands/devtools.js +239 -0
- package/dist/commands/docs.d.ts.map +1 -1
- package/dist/commands/docs.js +69 -1
- package/dist/commands/doctor.js +12 -4
- package/dist/commands/env.d.ts.map +1 -1
- package/dist/commands/env.js +3 -63
- package/dist/commands/init.d.ts +1 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +54 -14
- package/dist/commands/scratch.js +1 -1
- package/dist/commands/tunnel.d.ts.map +1 -1
- package/dist/commands/tunnel.js +273 -62
- package/dist/commands/web-fetch.js +1 -1
- package/dist/core/agents/cli.js +48 -0
- package/dist/core/agents/coord-client.d.ts.map +1 -1
- package/dist/core/agents/coord-client.js +32 -8
- package/dist/core/agents/events/emit.d.ts.map +1 -1
- package/dist/core/agents/events/emit.js +4 -0
- package/dist/core/agents/rules/claim-conflict.d.ts.map +1 -1
- package/dist/core/agents/rules/claim-conflict.js +16 -5
- package/dist/core/agents/state/heartbeat-projector.d.ts.map +1 -1
- package/dist/core/agents/state/heartbeat-projector.js +10 -3
- package/dist/core/config.d.ts +10 -0
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +13 -0
- package/dist/core/hooks/cli.js +3 -3
- package/dist/core/hooks/effects/index.d.ts +11 -7
- package/dist/core/hooks/effects/index.d.ts.map +1 -1
- package/dist/core/hooks/effects/index.js +15 -18
- package/dist/core/hooks/events/emit.d.ts.map +1 -1
- package/dist/core/hooks/events/emit.js +4 -0
- package/dist/core/hooks/events/rotate.d.ts +43 -0
- package/dist/core/hooks/events/rotate.d.ts.map +1 -0
- package/dist/core/hooks/events/rotate.js +142 -0
- package/dist/core/hooks/harness/events.d.ts +11 -1
- package/dist/core/hooks/harness/events.d.ts.map +1 -1
- package/dist/core/hooks/harness/events.js +22 -3
- package/dist/core/hooks/harness/wiring.d.ts +8 -0
- package/dist/core/hooks/harness/wiring.d.ts.map +1 -1
- package/dist/core/hooks/harness/wiring.js +34 -5
- package/dist/core/scratch/index.d.ts.map +1 -0
- package/dist/{lib → core}/scratch/index.js +2 -2
- package/dist/lib/devtools.d.ts +178 -0
- package/dist/lib/devtools.d.ts.map +1 -0
- package/dist/lib/devtools.js +1328 -0
- package/dist/lib/docs-frontmatter-migrate.d.ts +33 -0
- package/dist/lib/docs-frontmatter-migrate.d.ts.map +1 -0
- package/dist/lib/docs-frontmatter-migrate.js +364 -0
- package/dist/lib/docs-frontmatter.d.ts +33 -0
- package/dist/lib/docs-frontmatter.d.ts.map +1 -0
- package/dist/lib/docs-frontmatter.js +130 -0
- package/dist/lib/docs-index.d.ts +1 -0
- package/dist/lib/docs-index.d.ts.map +1 -1
- package/dist/lib/docs-index.js +4 -5
- package/dist/lib/docs-lint.d.ts +2 -0
- package/dist/lib/docs-lint.d.ts.map +1 -1
- package/dist/lib/docs-lint.js +18 -12
- package/dist/lib/docs-meta.d.ts +14 -0
- package/dist/lib/docs-meta.d.ts.map +1 -0
- package/dist/lib/docs-meta.js +34 -0
- package/dist/lib/docs-sweep.d.ts +12 -0
- package/dist/lib/docs-sweep.d.ts.map +1 -1
- package/dist/lib/docs-sweep.js +98 -103
- package/dist/lib/format.js +2 -2
- package/dist/lib/http/index.d.ts +1 -0
- package/dist/lib/http/index.d.ts.map +1 -1
- package/dist/lib/http/index.js +1 -0
- package/dist/lib/http/request.d.ts +77 -0
- package/dist/lib/http/request.d.ts.map +1 -0
- package/dist/lib/http/request.js +105 -0
- package/dist/lib/instructions/apply.d.ts +63 -0
- package/dist/lib/instructions/apply.d.ts.map +1 -0
- package/dist/lib/instructions/apply.js +255 -0
- package/dist/lib/instructions/splice.d.ts +73 -0
- package/dist/lib/instructions/splice.d.ts.map +1 -0
- package/dist/lib/instructions/splice.js +118 -0
- package/dist/lib/instructions/templates.d.ts +45 -0
- package/dist/lib/instructions/templates.d.ts.map +1 -0
- package/dist/lib/instructions/templates.js +258 -0
- package/dist/lib/tunnel/gate.d.ts +1 -0
- package/dist/lib/tunnel/gate.d.ts.map +1 -1
- package/dist/lib/tunnel/gate.js +14 -9
- package/dist/lib/tunnel/state.d.ts +11 -1
- package/dist/lib/tunnel/state.d.ts.map +1 -1
- package/dist/lib/tunnel/state.js +8 -3
- package/package.json +7 -6
- package/src/commander.ts +23 -0
- package/src/commands/agents.ts +50 -3
- package/src/commands/deinit.ts +5 -0
- package/src/commands/devtools.ts +284 -0
- package/src/commands/docs.ts +81 -1
- package/src/commands/doctor.ts +13 -4
- package/src/commands/env.ts +11 -77
- package/src/commands/init.ts +66 -15
- package/src/commands/scratch.ts +1 -1
- package/src/commands/tunnel.ts +316 -65
- package/src/commands/web-fetch.ts +1 -1
- package/src/core/agents/cli.ts +55 -0
- package/src/core/agents/coord-client.ts +34 -7
- package/src/core/agents/events/emit.ts +5 -0
- package/src/core/agents/rules/claim-conflict.ts +17 -6
- package/src/core/agents/state/heartbeat-projector.ts +11 -3
- package/src/core/config.ts +14 -0
- package/src/core/hooks/cli.ts +3 -3
- package/src/core/hooks/effects/index.ts +23 -17
- package/src/core/hooks/events/emit.ts +5 -0
- package/src/core/hooks/events/rotate.ts +151 -0
- package/src/core/hooks/harness/events.ts +30 -3
- package/src/core/hooks/harness/wiring.ts +46 -5
- package/src/{lib → core}/scratch/index.ts +2 -2
- package/src/lib/devtools.ts +1653 -0
- package/src/lib/docs-frontmatter-migrate.ts +427 -0
- package/src/lib/docs-frontmatter.ts +151 -0
- package/src/lib/docs-index.ts +4 -5
- package/src/lib/docs-lint.ts +17 -11
- package/src/lib/docs-meta.ts +44 -0
- package/src/lib/docs-sweep.ts +104 -102
- package/src/lib/format.ts +2 -2
- package/src/lib/http/index.ts +1 -0
- package/src/lib/http/request.ts +154 -0
- package/src/lib/instructions/apply.ts +318 -0
- package/src/lib/instructions/splice.ts +148 -0
- package/src/lib/instructions/templates.ts +295 -0
- package/src/lib/tunnel/gate.ts +14 -9
- package/src/lib/tunnel/state.ts +19 -4
- package/dist/lib/scratch/index.d.ts.map +0 -1
- /package/dist/{lib → core}/scratch/index.d.ts +0 -0
|
@@ -37,19 +37,35 @@ export const CURSOR_EVENTS = [
|
|
|
37
37
|
{ settingsKey: "beforeSubmitPrompt", subcommand: "user-prompt-submit" },
|
|
38
38
|
{ settingsKey: "stop", subcommand: "stop" },
|
|
39
39
|
];
|
|
40
|
-
/** Codex
|
|
40
|
+
/** Codex events that harnery uses from the current native lifecycle surface. */
|
|
41
41
|
export const CODEX_EVENTS = [
|
|
42
42
|
{ settingsKey: "SessionStart", subcommand: "session-start" },
|
|
43
|
-
{ settingsKey: "SessionEnd", subcommand: "session-end" },
|
|
44
43
|
{ settingsKey: "PreToolUse", subcommand: "pre-tool-use" },
|
|
45
44
|
{ settingsKey: "PostToolUse", subcommand: "post-tool-use" },
|
|
46
|
-
{ settingsKey: "PostToolUseFailure", subcommand: "post-tool-use-failure" },
|
|
47
45
|
{ settingsKey: "UserPromptSubmit", subcommand: "user-prompt-submit" },
|
|
48
46
|
{ settingsKey: "SubagentStart", subcommand: "sub-agent-start" },
|
|
49
47
|
{ settingsKey: "SubagentStop", subcommand: "sub-agent-stop" },
|
|
50
48
|
{ settingsKey: "Stop", subcommand: "stop" },
|
|
49
|
+
];
|
|
50
|
+
/** Entries written by harnery before Codex adopted a strict native hook schema. */
|
|
51
|
+
export const LEGACY_CODEX_EVENTS = [
|
|
52
|
+
{ settingsKey: "SessionEnd", subcommand: "session-end" },
|
|
53
|
+
{ settingsKey: "PostToolUseFailure", subcommand: "post-tool-use-failure" },
|
|
51
54
|
{ settingsKey: "StopFailure", subcommand: "stop-failure" },
|
|
52
55
|
];
|
|
56
|
+
/** Every hook key accepted by Codex 0.144, including events harnery does not consume. */
|
|
57
|
+
export const CODEX_ALLOWED_EVENT_KEYS = [
|
|
58
|
+
"SessionStart",
|
|
59
|
+
"PreToolUse",
|
|
60
|
+
"PermissionRequest",
|
|
61
|
+
"PostToolUse",
|
|
62
|
+
"PreCompact",
|
|
63
|
+
"PostCompact",
|
|
64
|
+
"UserPromptSubmit",
|
|
65
|
+
"SubagentStart",
|
|
66
|
+
"SubagentStop",
|
|
67
|
+
"Stop",
|
|
68
|
+
];
|
|
53
69
|
/** Every supported harness, fully wireable by `harn init`. */
|
|
54
70
|
export const HARNESS_SPECS = {
|
|
55
71
|
"claude-code": {
|
|
@@ -67,5 +83,8 @@ export const HARNESS_SPECS = {
|
|
|
67
83
|
settingsFile: ".codex/hooks.json",
|
|
68
84
|
events: CODEX_EVENTS,
|
|
69
85
|
entryShape: "claude",
|
|
86
|
+
legacyEvents: LEGACY_CODEX_EVENTS,
|
|
87
|
+
allowedTopLevelKeys: ["description", "hooks"],
|
|
88
|
+
allowedEventKeys: CODEX_ALLOWED_EVENT_KEYS,
|
|
70
89
|
},
|
|
71
90
|
};
|
|
@@ -28,6 +28,7 @@ export interface CursorHookGroup {
|
|
|
28
28
|
export type HookGroup = ClaudeHookGroup | CursorHookGroup;
|
|
29
29
|
export interface SettingsFile {
|
|
30
30
|
version?: number;
|
|
31
|
+
description?: string;
|
|
31
32
|
hooks?: Record<string, HookGroup[]>;
|
|
32
33
|
[k: string]: unknown;
|
|
33
34
|
}
|
|
@@ -51,6 +52,10 @@ export interface WiringDiff {
|
|
|
51
52
|
* these — they need explicit removal — so they're surfaced separately.
|
|
52
53
|
*/
|
|
53
54
|
orphans: string[];
|
|
55
|
+
/** Settings fields rejected by a harness with a strict top-level schema. */
|
|
56
|
+
invalidTopLevelKeys: string[];
|
|
57
|
+
/** Hook event names rejected by a harness with a strict event schema. */
|
|
58
|
+
invalidEventKeys: string[];
|
|
54
59
|
}
|
|
55
60
|
/**
|
|
56
61
|
* Pure diff of one settings object against one harness spec. Read-only inverse
|
|
@@ -63,6 +68,9 @@ export interface HarnessWiringStatus {
|
|
|
63
68
|
settingsFile: string;
|
|
64
69
|
missing: HookEvent[];
|
|
65
70
|
orphans: string[];
|
|
71
|
+
invalidTopLevelKeys: string[];
|
|
72
|
+
invalidEventKeys: string[];
|
|
73
|
+
parseError?: string;
|
|
66
74
|
}
|
|
67
75
|
/**
|
|
68
76
|
* Inspect every harness whose settings file exists under `projectRoot` and
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wiring.d.ts","sourceRoot":"","sources":["../../../../src/core/hooks/harness/wiring.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAKH,OAAO,EAEL,KAAK,SAAS,EACd,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,KAAK,SAAS,EACf,MAAM,aAAa,CAAC;AAErB,mEAAmE;AACnE,MAAM,WAAW,eAAe;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAC5C;AACD,0CAA0C;AAC1C,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AACD,MAAM,MAAM,SAAS,GAAG,eAAe,GAAG,eAAe,CAAC;AAE1D,MAAM,WAAW,YAAY;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;IACpC,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AAED,iDAAiD;AACjD,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,GAAG,SAAS,CAE3E;AAED,0EAA0E;AAC1E,wBAAgB,aAAa,CAAC,KAAK,EAAE,SAAS,GAAG,MAAM,EAAE,CAMxD;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAEnF;AAQD,MAAM,WAAW,UAAU;IACzB,kDAAkD;IAClD,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB,iCAAiC;IACjC,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB;;;;OAIG;IACH,OAAO,EAAE,MAAM,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"wiring.d.ts","sourceRoot":"","sources":["../../../../src/core/hooks/harness/wiring.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAKH,OAAO,EAEL,KAAK,SAAS,EACd,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,KAAK,SAAS,EACf,MAAM,aAAa,CAAC;AAErB,mEAAmE;AACnE,MAAM,WAAW,eAAe;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAC5C;AACD,0CAA0C;AAC1C,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AACD,MAAM,MAAM,SAAS,GAAG,eAAe,GAAG,eAAe,CAAC;AAE1D,MAAM,WAAW,YAAY;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;IACpC,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AAED,iDAAiD;AACjD,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,GAAG,SAAS,CAE3E;AAED,0EAA0E;AAC1E,wBAAgB,aAAa,CAAC,KAAK,EAAE,SAAS,GAAG,MAAM,EAAE,CAMxD;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAEnF;AAQD,MAAM,WAAW,UAAU;IACzB,kDAAkD;IAClD,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB,iCAAiC;IACjC,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB;;;;OAIG;IACH,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,4EAA4E;IAC5E,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,yEAAyE;IACzE,gBAAgB,EAAE,MAAM,EAAE,CAAC;CAC5B;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,YAAY,EAAE,IAAI,EAAE,WAAW,GAAG,UAAU,CA2ChF;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,SAAS,CAAC;IACnB,wDAAwD;IACxD,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,mBAAmB,EAAE,CAwC5E;AAED;;;;GAIG;AACH,wBAAgB,cAAc,IAAI,MAAM,CAkBvC"}
|
|
@@ -65,7 +65,23 @@ export function diffWiring(settings, spec) {
|
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
|
-
|
|
68
|
+
const invalidTopLevelKeys = spec.allowedTopLevelKeys
|
|
69
|
+
? Object.keys(settings)
|
|
70
|
+
.filter((key) => !spec.allowedTopLevelKeys.includes(key))
|
|
71
|
+
.sort()
|
|
72
|
+
: [];
|
|
73
|
+
const invalidEventKeys = spec.allowedEventKeys
|
|
74
|
+
? Object.keys(hooks)
|
|
75
|
+
.filter((key) => !spec.allowedEventKeys.includes(key))
|
|
76
|
+
.sort()
|
|
77
|
+
: [];
|
|
78
|
+
return {
|
|
79
|
+
missing,
|
|
80
|
+
present,
|
|
81
|
+
orphans: [...orphans].sort(),
|
|
82
|
+
invalidTopLevelKeys,
|
|
83
|
+
invalidEventKeys,
|
|
84
|
+
};
|
|
69
85
|
}
|
|
70
86
|
/**
|
|
71
87
|
* Inspect every harness whose settings file exists under `projectRoot` and
|
|
@@ -88,21 +104,34 @@ export function loadHarnessWiring(projectRoot) {
|
|
|
88
104
|
try {
|
|
89
105
|
settings = JSON.parse(readFileSync(settingsPath, "utf8"));
|
|
90
106
|
}
|
|
91
|
-
catch {
|
|
92
|
-
|
|
93
|
-
|
|
107
|
+
catch (error) {
|
|
108
|
+
out.push({
|
|
109
|
+
harness: id,
|
|
110
|
+
settingsFile: spec.settingsFile,
|
|
111
|
+
missing: [],
|
|
112
|
+
orphans: [],
|
|
113
|
+
invalidTopLevelKeys: [],
|
|
114
|
+
invalidEventKeys: [],
|
|
115
|
+
parseError: error.message,
|
|
116
|
+
});
|
|
94
117
|
continue;
|
|
95
118
|
}
|
|
96
119
|
const diff = diffWiring(settings, spec);
|
|
97
120
|
if (diff.present.length === 0)
|
|
98
121
|
continue; // not opted in → not drift
|
|
99
|
-
if (diff.missing.length === 0 &&
|
|
122
|
+
if (diff.missing.length === 0 &&
|
|
123
|
+
diff.orphans.length === 0 &&
|
|
124
|
+
diff.invalidTopLevelKeys.length === 0 &&
|
|
125
|
+
diff.invalidEventKeys.length === 0) {
|
|
100
126
|
continue; // current
|
|
127
|
+
}
|
|
101
128
|
out.push({
|
|
102
129
|
harness: id,
|
|
103
130
|
settingsFile: spec.settingsFile,
|
|
104
131
|
missing: diff.missing,
|
|
105
132
|
orphans: diff.orphans,
|
|
133
|
+
invalidTopLevelKeys: diff.invalidTopLevelKeys,
|
|
134
|
+
invalidEventKeys: diff.invalidEventKeys,
|
|
106
135
|
});
|
|
107
136
|
}
|
|
108
137
|
return out;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/scratch/index.ts"],"names":[],"mappings":"AAcA;;;;;;;;;;;;GAYG;AAEH,eAAO,MAAM,kBAAkB,iFAQrB,CAAC;AAEX,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,kBAAkB,CAAC,CAAC,MAAM,CAAC,CAAC;AAElE,eAAO,MAAM,iBAAiB,QAAY,CAAC;AAC3C,eAAO,MAAM,kBAAkB,QAAY,CAAC;AAC5C,eAAO,MAAM,sBAAsB,IAAI,CAAC;AAExC,6DAA6D;AAC7D,eAAO,MAAM,eAAe,QACyF,CAAC;AAEtH,mFAAmF;AACnF,eAAO,MAAM,wBAAwB,yBAAyB,CAAC;AAE/D,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,eAAe,CAAC;IAC1B,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,aAAa,CAAC;IACtB,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;CACf;AAID,wBAAgB,UAAU,IAAI,MAAM,CAMnC;AAED,wBAAgB,UAAU,IAAI,MAAM,CAInC;AAED,wBAAgB,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAEtD;AAeD,8EAA8E;AAC9E,wBAAgB,aAAa,CAAC,CAAC,GAAE,IAAiB,GAAG,MAAM,CAW1D;AAID,wEAAwE;AACxE,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,UAAU,CA+DtE;AAED,+CAA+C;AAC/C,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,UAAU,GAAG,MAAM,CAkBxD;AAmBD,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,SAAoB,GAAG,SAAS,EAAE,CA2DrF;AAID,wBAAgB,WAAW,CACzB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,eAAe,EACzB,IAAI,EAAE,MAAM,GACX,UAAU,CAgEZ;AAID,wGAAwG;AACxG,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAOhE;AAED,iEAAiE;AACjE,wBAAgB,aAAa,CAAC,IAAI,SAAyB,GAAG,MAAM,CAkBnE;AAED,uFAAuF;AACvF,wBAAgB,sBAAsB,IAAI,MAAM,EAAE,CAajD;AAED,qDAAqD;AACrD,wBAAgB,YAAY,IAAI;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACf,EAAE,CAWF;AAID,wBAAgB,mBAAmB,IAAI,MAAM,CAM5C;AAED,wBAAgB,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAIjE;AAED,2FAA2F;AAC3F,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAoB9D"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, readdirSync, readFileSync, renameSync, statSync, unlinkSync, writeFileSync, } from "node:fs";
|
|
2
2
|
import { dirname, resolve } from "node:path";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { resolveMachineLabel } from "../../lib/machine.js";
|
|
4
|
+
import { monorepoRoot, readHeartbeat, resolveOwner } from "../agents/index.js";
|
|
5
5
|
/**
|
|
6
6
|
* Agent scratchpad: per-agent markdown journal at `.harnery/scratch/<instance_id>.md`.
|
|
7
7
|
*
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `devtools`: read locally-stored state of the AI coding agents harnery
|
|
3
|
+
* supports — Claude Code (`~/.claude`), Codex (`~/.codex`), and Cursor
|
|
4
|
+
* (`~/.cursor`) — into one uniform status shape: login state, plan/tier,
|
|
5
|
+
* auth expiry, session counts, and (where the tool stores them locally)
|
|
6
|
+
* rate-limit / quota windows.
|
|
7
|
+
*
|
|
8
|
+
* Everything here reads files on disk — no network, no vendor API, no
|
|
9
|
+
* credentials leave the machine (auth tokens are inspected for their
|
|
10
|
+
* non-secret claims only; the token strings themselves are never returned).
|
|
11
|
+
* The signals a tool keeps server-side (Cursor usage + billing, Claude's live
|
|
12
|
+
* rate-limit windows) surface as `null` with a note rather than a guess.
|
|
13
|
+
*
|
|
14
|
+
* Pure toolkit tier: depends only on `node:*`, never on `src/core/`.
|
|
15
|
+
*/
|
|
16
|
+
export type DevtoolName = "claude-code" | "codex" | "cursor";
|
|
17
|
+
export interface QuotaWindow {
|
|
18
|
+
/** Human label for the reset window (e.g. "5h", "weekly", "45m"). */
|
|
19
|
+
window: string;
|
|
20
|
+
/** Percent of the window's allowance consumed, 0-100, or null if unknown. */
|
|
21
|
+
usedPercent: number | null;
|
|
22
|
+
/** ISO timestamp when the window resets, or null if unknown. */
|
|
23
|
+
resetsAt: string | null;
|
|
24
|
+
}
|
|
25
|
+
export interface ApiEnrichment {
|
|
26
|
+
/** The configured API key authenticated successfully. */
|
|
27
|
+
ok: boolean;
|
|
28
|
+
/** Human name the vendor reports for the key (e.g. Cursor's apiKeyName). */
|
|
29
|
+
keyName: string | null;
|
|
30
|
+
/** Cloud-agent activity (Cursor Cloud Agent API), when available. */
|
|
31
|
+
cloudAgents: {
|
|
32
|
+
total: number;
|
|
33
|
+
active: number;
|
|
34
|
+
} | null;
|
|
35
|
+
/** Error message when the key is configured but a call failed. */
|
|
36
|
+
error: string | null;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Cursor billing-cycle + usage snapshot, fetched from cursor.com's own dashboard
|
|
40
|
+
* API using the IDE's locally-stored session token — the same call Cursor's UI
|
|
41
|
+
* makes for the Spending page. No API key to mint; it reads what's already on
|
|
42
|
+
* disk. Percentages are 0-100; cent amounts are raw (divide by 100 for dollars).
|
|
43
|
+
*/
|
|
44
|
+
export interface CursorUsage {
|
|
45
|
+
/** ISO start of the current billing cycle. */
|
|
46
|
+
cycleStart: string | null;
|
|
47
|
+
/** ISO end of the current billing cycle (the "resets on …" date). */
|
|
48
|
+
cycleEnd: string | null;
|
|
49
|
+
/** Percent of included total usage consumed this cycle (Cursor's "Total"). */
|
|
50
|
+
totalPercentUsed: number | null;
|
|
51
|
+
/** Percent of included API usage consumed (named-model / "API"). */
|
|
52
|
+
apiPercentUsed: number | null;
|
|
53
|
+
/** Percent of included first-party ("Auto") model usage consumed. */
|
|
54
|
+
firstPartyPercentUsed: number | null;
|
|
55
|
+
/** Included usage allowance in cents (e.g. 7000 = $70). */
|
|
56
|
+
includedLimitCents: number | null;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Overage / on-demand dollar spend against a cap — Cursor's on-demand usage and
|
|
60
|
+
* Claude's extra-usage credits are the same idea. Cents are raw (÷100 for USD).
|
|
61
|
+
*/
|
|
62
|
+
export interface SpendStatus {
|
|
63
|
+
/** Human label for what this spend covers (e.g. "On-demand", "Extra usage"). */
|
|
64
|
+
label: string;
|
|
65
|
+
/** Amount spent this cycle in cents. */
|
|
66
|
+
usedCents: number | null;
|
|
67
|
+
/** Spend cap in cents, or null when unset/unlimited. */
|
|
68
|
+
limitCents: number | null;
|
|
69
|
+
}
|
|
70
|
+
export interface ToolStatus {
|
|
71
|
+
tool: DevtoolName;
|
|
72
|
+
/** The tool's config directory exists on this machine. */
|
|
73
|
+
installed: boolean;
|
|
74
|
+
/** A credential is present and not obviously expired. null when undeterminable. */
|
|
75
|
+
loggedIn: boolean | null;
|
|
76
|
+
/** Account identifier (email where the tool exposes one), else null. */
|
|
77
|
+
account: string | null;
|
|
78
|
+
/** Plan / seat tier as the tool records it locally (e.g. "team", "team_tier_1"). */
|
|
79
|
+
plan: string | null;
|
|
80
|
+
/** Rate-limit tier string where the tool records one, else null. */
|
|
81
|
+
rateLimitTier: string | null;
|
|
82
|
+
/** ISO expiry of the active access credential, else null. */
|
|
83
|
+
authExpiresAt: string | null;
|
|
84
|
+
/** Count of local session transcripts, else null. */
|
|
85
|
+
sessions: number | null;
|
|
86
|
+
/** ISO timestamp of the most recent local session activity, else null. */
|
|
87
|
+
lastActivity: string | null;
|
|
88
|
+
/** Locally-known quota/rate-limit windows, or null when the tool keeps them server-side. */
|
|
89
|
+
quota: QuotaWindow[] | null;
|
|
90
|
+
/**
|
|
91
|
+
* Total tokens observed in local transcripts within the scan window
|
|
92
|
+
* (`windowDays`). Codex always reports it — its per-session cumulative total
|
|
93
|
+
* is one tail-read per rollout, cheap enough for every render. Claude Code's
|
|
94
|
+
* is `--usage`-gated (a full transcript scan, potentially gigabytes) and null
|
|
95
|
+
* otherwise. Cursor keeps token counts server-side, so it stays null.
|
|
96
|
+
*/
|
|
97
|
+
tokensUsed: number | null;
|
|
98
|
+
/**
|
|
99
|
+
* Result of the optional API enrichment (network), populated by
|
|
100
|
+
* `enrichFromApi` when a key is configured. `null` when no enrichment ran.
|
|
101
|
+
*/
|
|
102
|
+
api: ApiEnrichment | null;
|
|
103
|
+
/**
|
|
104
|
+
* Cursor billing-cycle + usage, populated by `enrichFromApi` from the IDE's
|
|
105
|
+
* own session token (no API key needed). `null` when no enrichment ran, the
|
|
106
|
+
* token is stale, or the tool isn't Cursor.
|
|
107
|
+
*/
|
|
108
|
+
usage: CursorUsage | null;
|
|
109
|
+
/**
|
|
110
|
+
* Overage / on-demand dollar spend, populated by `enrichFromApi` (Cursor's
|
|
111
|
+
* on-demand, Claude's extra-usage credits). `null` when no enrichment ran or
|
|
112
|
+
* the plan has no overage concept.
|
|
113
|
+
*/
|
|
114
|
+
spend: SpendStatus | null;
|
|
115
|
+
/** Caveats about what is and isn't derivable locally for this tool. */
|
|
116
|
+
notes: string[];
|
|
117
|
+
}
|
|
118
|
+
export interface DevtoolsReport {
|
|
119
|
+
generatedAt: string;
|
|
120
|
+
windowDays: number | null;
|
|
121
|
+
tools: ToolStatus[];
|
|
122
|
+
}
|
|
123
|
+
/** One endpoint's health, from `probeEndpoints` (the `devtools doctor` check). */
|
|
124
|
+
export interface ProbeResult {
|
|
125
|
+
tool: DevtoolName;
|
|
126
|
+
endpoint: string;
|
|
127
|
+
/** Client version we put in the request's User-Agent, else null. */
|
|
128
|
+
clientVersion: string | null;
|
|
129
|
+
/** HTTP status, or null when no call was made / the request threw. */
|
|
130
|
+
status: number | null;
|
|
131
|
+
outcome: "ok" | "rate_limited" | "auth_rejected" | "shape_changed" | "unreachable" | "no_credential";
|
|
132
|
+
detail: string;
|
|
133
|
+
}
|
|
134
|
+
export interface ReadDevtoolsOpts {
|
|
135
|
+
/** Home directory to resolve tool config against. Defaults to os.homedir(). */
|
|
136
|
+
home?: string;
|
|
137
|
+
/** Scan transcripts for token totals (opt-in; can be slow). Default false. */
|
|
138
|
+
usage?: boolean;
|
|
139
|
+
/** When scanning usage, only include transcripts modified within N days. Default 7. */
|
|
140
|
+
windowDays?: number;
|
|
141
|
+
/** Clock injection for tests. Default Date.now(). */
|
|
142
|
+
now?: number;
|
|
143
|
+
/** Restrict to a subset of tools. Default all three. */
|
|
144
|
+
only?: readonly DevtoolName[];
|
|
145
|
+
}
|
|
146
|
+
/** Path of the machine-local Cursor API key file (honors XDG_CONFIG_HOME). */
|
|
147
|
+
export declare function cursorApiKeyPath(): string;
|
|
148
|
+
/** Resolve a Cursor API key: env `CURSOR_API_KEY` first, then the key file. */
|
|
149
|
+
export declare function resolveCursorApiKey(): string | null;
|
|
150
|
+
/**
|
|
151
|
+
* Enrich a report's entries over the network with live usage each tool keeps
|
|
152
|
+
* server-side, authenticating with the credential already on disk. Best-effort
|
|
153
|
+
* and network-guarded: every failure degrades to a note, never throws. No-op
|
|
154
|
+
* for a tool that isn't installed / present in the report.
|
|
155
|
+
*/
|
|
156
|
+
export declare function enrichFromApi(report: DevtoolsReport, opts?: {
|
|
157
|
+
cursorKey?: string | null;
|
|
158
|
+
timeoutMs?: number;
|
|
159
|
+
home?: string;
|
|
160
|
+
/** Cache TTL for the usage endpoints (ms). 0 disables caching. Default 120s. */
|
|
161
|
+
cacheTtlMs?: number;
|
|
162
|
+
}): Promise<DevtoolsReport>;
|
|
163
|
+
/**
|
|
164
|
+
* One live call per usage endpoint (cache-bypassing) to check the integration
|
|
165
|
+
* still works — the occasional "did a client change its headers?" test. It
|
|
166
|
+
* exercises the EXACT request builders production uses, so an `auth_rejected`
|
|
167
|
+
* result means our headers/token stopped being accepted, and `shape_changed`
|
|
168
|
+
* means the response schema drifted. Rate-limited results are reported as such,
|
|
169
|
+
* not as failures. Makes at most one request per tool; run it by hand (it is not
|
|
170
|
+
* scheduled) so it can't itself cause a rate limit.
|
|
171
|
+
*/
|
|
172
|
+
export declare function probeEndpoints(opts?: {
|
|
173
|
+
home?: string;
|
|
174
|
+
timeoutMs?: number;
|
|
175
|
+
only?: readonly DevtoolName[];
|
|
176
|
+
}): Promise<ProbeResult[]>;
|
|
177
|
+
export declare function readDevtools(opts?: ReadDevtoolsOpts): DevtoolsReport;
|
|
178
|
+
//# sourceMappingURL=devtools.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"devtools.d.ts","sourceRoot":"","sources":["../../src/lib/devtools.ts"],"names":[],"mappings":"AAmBA;;;;;;;;;;;;;;GAcG;AAEH,MAAM,MAAM,WAAW,GAAG,aAAa,GAAG,OAAO,GAAG,QAAQ,CAAC;AAE7D,MAAM,WAAW,WAAW;IAC1B,qEAAqE;IACrE,MAAM,EAAE,MAAM,CAAC;IACf,6EAA6E;IAC7E,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,gEAAgE;IAChE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED,MAAM,WAAW,aAAa;IAC5B,yDAAyD;IACzD,EAAE,EAAE,OAAO,CAAC;IACZ,4EAA4E;IAC5E,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,qEAAqE;IACrE,WAAW,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACtD,kEAAkE;IAClE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED;;;;;GAKG;AACH,MAAM,WAAW,WAAW;IAC1B,8CAA8C;IAC9C,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,qEAAqE;IACrE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,8EAA8E;IAC9E,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,oEAAoE;IACpE,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,qEAAqE;IACrE,qBAAqB,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,2DAA2D;IAC3D,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;CACnC;AAED;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,gFAAgF;IAChF,KAAK,EAAE,MAAM,CAAC;IACd,wCAAwC;IACxC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,wDAAwD;IACxD,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,WAAW,CAAC;IAClB,0DAA0D;IAC1D,SAAS,EAAE,OAAO,CAAC;IACnB,mFAAmF;IACnF,QAAQ,EAAE,OAAO,GAAG,IAAI,CAAC;IACzB,wEAAwE;IACxE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,oFAAoF;IACpF,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,oEAAoE;IACpE,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,6DAA6D;IAC7D,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,qDAAqD;IACrD,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,0EAA0E;IAC1E,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,4FAA4F;IAC5F,KAAK,EAAE,WAAW,EAAE,GAAG,IAAI,CAAC;IAC5B;;;;;;OAMG;IACH,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B;;;OAGG;IACH,GAAG,EAAE,aAAa,GAAG,IAAI,CAAC;IAC1B;;;;OAIG;IACH,KAAK,EAAE,WAAW,GAAG,IAAI,CAAC;IAC1B;;;;OAIG;IACH,KAAK,EAAE,WAAW,GAAG,IAAI,CAAC;IAC1B,uEAAuE;IACvE,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,KAAK,EAAE,UAAU,EAAE,CAAC;CACrB;AAED,kFAAkF;AAClF,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,WAAW,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,oEAAoE;IACpE,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,sEAAsE;IACtE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,OAAO,EACH,IAAI,GACJ,cAAc,GACd,eAAe,GACf,eAAe,GACf,aAAa,GACb,eAAe,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,gBAAgB;IAC/B,+EAA+E;IAC/E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,8EAA8E;IAC9E,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,uFAAuF;IACvF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,qDAAqD;IACrD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,wDAAwD;IACxD,IAAI,CAAC,EAAE,SAAS,WAAW,EAAE,CAAC;CAC/B;AAsBD,8EAA8E;AAC9E,wBAAgB,gBAAgB,IAAI,MAAM,CAIzC;AAED,+EAA+E;AAC/E,wBAAgB,mBAAmB,IAAI,MAAM,GAAG,IAAI,CASnD;AAsGD;;;;;GAKG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,cAAc,EACtB,IAAI,GAAE;IACJ,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,gFAAgF;IAChF,UAAU,CAAC,EAAE,MAAM,CAAC;CAChB,GACL,OAAO,CAAC,cAAc,CAAC,CAiEzB;AAED;;;;;;;;GAQG;AACH,wBAAsB,cAAc,CAClC,IAAI,GAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,SAAS,WAAW,EAAE,CAAA;CAAO,GAC9E,OAAO,CAAC,WAAW,EAAE,CAAC,CAyCxB;AAkdD,wBAAgB,YAAY,CAAC,IAAI,GAAE,gBAAqB,GAAG,cAAc,CAmBxE"}
|