@hizliemre/horse-code 0.3.0 → 0.4.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/dist/{app-5FXHE7GX.js → app-KR7TAHUD.js} +82 -40
- package/dist/{chunk-LNW557IO.js → chunk-372X5HHU.js} +2 -2
- package/dist/{chunk-XEGQT5EN.js → chunk-4M6LXNG2.js} +1 -1
- package/dist/{chunk-6OSEQOYY.js → chunk-6S4WWQMN.js} +2 -2
- package/dist/chunk-ACTVFJRW.js +989 -0
- package/dist/{chunk-LLL7QWXB.js → chunk-BFIZMM4G.js} +6 -6
- package/dist/chunk-CYLPQWIF.js +214 -0
- package/dist/{chunk-AE36LLL2.js → chunk-JLWQCA7B.js} +2 -209
- package/dist/{chunk-XYZVZPAY.js → chunk-KXBYRU4W.js} +66 -31
- package/dist/chunk-MZM24M5M.js +251 -0
- package/dist/chunk-NBTH2VVI.js +1945 -0
- package/dist/chunk-PIG54WFU.js +2873 -0
- package/dist/{run-P6ZYL5JL.js → chunk-QJYVZPLG.js} +133 -389
- package/dist/{chunk-YPZP7LYL.js → chunk-UANNVVIU.js} +1 -1
- package/dist/{chunk-UGESK765.js → chunk-UTHLEW5V.js} +1 -1
- package/dist/{chunk-KAGKX2YT.js → chunk-ZPJP2VH5.js} +10 -1
- package/dist/cli.js +262 -69
- package/dist/{fix-ONLA45HD.js → fix-SSDUVV4T.js} +11 -8
- package/dist/{ongoing-WHYXPW24.js → ongoing-6NUSPSCV.js} +3 -2
- package/dist/{project-graph-5HNPRFQG.js → project-graph-OGIM2B33.js} +1 -1
- package/dist/research-MHBNZ6SA.js +111 -0
- package/dist/run-V5ZLZ3LS.js +274 -0
- package/dist/{save-skills-ZW5GY6KV.js → save-skills-NPKTYNAF.js} +2 -2
- package/dist/{trace-X6TU3AG6.js → trace-UVMZZRA5.js} +1 -1
- package/dist/{trace-adopt-URECQWJV.js → trace-adopt-7HWELJFE.js} +1 -1
- package/dist/{trace-run-7U4WJZ3V.js → trace-run-OBOD552Q.js} +9 -4
- package/dist/{triage-FCYHD2AQ.js → triage-IFCVL5MA.js} +7 -6
- package/dist/{verify-LC57A6H2.js → verify-2DTBG6RG.js} +26 -20
- package/package.json +1 -1
- package/dist/chunk-MRZVA5JB.js +0 -163
- package/dist/chunk-UEWVVN5L.js +0 -5691
- package/dist/{chunk-EAF22QIG.js → chunk-JR2JLRE3.js} +3 -3
package/dist/cli.js
CHANGED
|
@@ -15,32 +15,28 @@ import {
|
|
|
15
15
|
restoreTerminal,
|
|
16
16
|
runJob,
|
|
17
17
|
sttySane
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-KXBYRU4W.js";
|
|
19
19
|
import "./chunk-M2RKCIGV.js";
|
|
20
|
+
import "./chunk-UTHLEW5V.js";
|
|
20
21
|
import {
|
|
21
|
-
CODE_TEAM,
|
|
22
22
|
CliProvider,
|
|
23
|
-
DEFAULT_COUNCIL,
|
|
24
|
-
DEFAULT_PROMPTS,
|
|
25
|
-
DEFAULT_ROLE_SKILLS,
|
|
26
|
-
PLAN_TEAM,
|
|
27
|
-
REQUIRED_ROLES,
|
|
28
23
|
RoleFitness,
|
|
29
|
-
RoleRegistry,
|
|
30
24
|
SHORT_CALL_MS,
|
|
31
|
-
SPEC_TEAM,
|
|
32
|
-
WorktreeManager,
|
|
33
|
-
ZAI_MODELS,
|
|
34
25
|
buildCouncilRegistry,
|
|
35
|
-
buildTeamRegistry
|
|
36
|
-
|
|
26
|
+
buildTeamRegistry
|
|
27
|
+
} from "./chunk-PIG54WFU.js";
|
|
28
|
+
import {
|
|
29
|
+
WorktreeManager,
|
|
37
30
|
mainWorktreeRoot,
|
|
38
|
-
modelsFor,
|
|
39
31
|
toSlug
|
|
40
|
-
} from "./chunk-
|
|
41
|
-
import "./chunk-QF4MP6BS.js";
|
|
42
|
-
import "./chunk-UGESK765.js";
|
|
32
|
+
} from "./chunk-NBTH2VVI.js";
|
|
43
33
|
import "./chunk-ZSQ24YDJ.js";
|
|
34
|
+
import "./chunk-QF4MP6BS.js";
|
|
35
|
+
import {
|
|
36
|
+
MAX_CHUNK_CHARS,
|
|
37
|
+
discover,
|
|
38
|
+
readFinding
|
|
39
|
+
} from "./chunk-QJYVZPLG.js";
|
|
44
40
|
import {
|
|
45
41
|
parseFrontmatter
|
|
46
42
|
} from "./chunk-BY4DP7IE.js";
|
|
@@ -48,58 +44,77 @@ import {
|
|
|
48
44
|
UNSET_MODEL,
|
|
49
45
|
loadConfig,
|
|
50
46
|
saveSkillSource
|
|
51
|
-
} from "./chunk-
|
|
52
|
-
import {
|
|
53
|
-
CLI_KINDS,
|
|
54
|
-
checkProfile,
|
|
55
|
-
runLogin
|
|
56
|
-
} from "./chunk-G45RWL7S.js";
|
|
47
|
+
} from "./chunk-JR2JLRE3.js";
|
|
57
48
|
import "./chunk-H2FDGPVW.js";
|
|
58
49
|
import {
|
|
50
|
+
RoleRegistry,
|
|
51
|
+
ZAI_MODELS,
|
|
59
52
|
buildBrief,
|
|
53
|
+
cliCatalog,
|
|
60
54
|
describePlan,
|
|
55
|
+
modelsFor,
|
|
61
56
|
planFor,
|
|
62
57
|
runTraces,
|
|
63
58
|
traceableFiles
|
|
64
|
-
} from "./chunk-
|
|
59
|
+
} from "./chunk-ACTVFJRW.js";
|
|
60
|
+
import {
|
|
61
|
+
CODE_TEAM,
|
|
62
|
+
DEFAULT_COUNCIL,
|
|
63
|
+
DEFAULT_PROMPTS,
|
|
64
|
+
DEFAULT_ROLE_SKILLS,
|
|
65
|
+
PLAN_TEAM,
|
|
66
|
+
REQUIRED_ROLES,
|
|
67
|
+
SPEC_TEAM
|
|
68
|
+
} from "./chunk-MZM24M5M.js";
|
|
69
|
+
import {
|
|
70
|
+
CLI_KINDS,
|
|
71
|
+
checkProfile,
|
|
72
|
+
runLogin
|
|
73
|
+
} from "./chunk-G45RWL7S.js";
|
|
65
74
|
import {
|
|
66
75
|
defaultGitRunner
|
|
67
76
|
} from "./chunk-LPQU436C.js";
|
|
68
77
|
import {
|
|
69
78
|
InjectionLog,
|
|
70
79
|
memoryNote
|
|
71
|
-
} from "./chunk-
|
|
80
|
+
} from "./chunk-BFIZMM4G.js";
|
|
81
|
+
import {
|
|
82
|
+
ToolRegistry
|
|
83
|
+
} from "./chunk-CYLPQWIF.js";
|
|
72
84
|
import "./chunk-63E73TGI.js";
|
|
85
|
+
import {
|
|
86
|
+
briefStatus
|
|
87
|
+
} from "./chunk-6S4WWQMN.js";
|
|
73
88
|
import {
|
|
74
89
|
Telemetry,
|
|
75
|
-
ToolRegistry,
|
|
76
90
|
clearPerfMarks,
|
|
77
91
|
sampleMemory,
|
|
78
92
|
setTelemetry,
|
|
79
93
|
stripThinking,
|
|
80
94
|
telemetry,
|
|
81
95
|
writeHeapSnapshot
|
|
82
|
-
} from "./chunk-
|
|
83
|
-
import {
|
|
84
|
-
briefStatus
|
|
85
|
-
} from "./chunk-6OSEQOYY.js";
|
|
96
|
+
} from "./chunk-JLWQCA7B.js";
|
|
86
97
|
import {
|
|
87
98
|
discoverTraceRoot,
|
|
88
|
-
|
|
89
|
-
|
|
99
|
+
ensureGitignore,
|
|
100
|
+
localOnly,
|
|
101
|
+
setTraceRoot,
|
|
102
|
+
sharedDerived,
|
|
103
|
+
traceRootRel
|
|
104
|
+
} from "./chunk-ZPJP2VH5.js";
|
|
90
105
|
import {
|
|
91
106
|
buildProjectGraph,
|
|
92
107
|
graphStatus,
|
|
93
108
|
graphifyPython
|
|
94
|
-
} from "./chunk-
|
|
109
|
+
} from "./chunk-4M6LXNG2.js";
|
|
95
110
|
import {
|
|
96
111
|
sessionBase
|
|
97
112
|
} from "./chunk-6W4UH2BQ.js";
|
|
98
113
|
|
|
99
114
|
// src/cli.ts
|
|
100
115
|
import { execFileSync } from "child_process";
|
|
101
|
-
import { readFileSync as readFileSync5, existsSync as
|
|
102
|
-
import { join as
|
|
116
|
+
import { readFileSync as readFileSync5, existsSync as existsSync4, writeFileSync as writeFileSync4, mkdirSync as mkdirSync5, realpathSync, rmSync, statSync as statSync2 } from "fs";
|
|
117
|
+
import { join as join12, dirname as dirname5 } from "path";
|
|
103
118
|
import { pathToFileURL } from "url";
|
|
104
119
|
|
|
105
120
|
// src/agents/cli-accounts.ts
|
|
@@ -694,6 +709,137 @@ async function syncSkillSources(home, sources, deps = {}) {
|
|
|
694
709
|
return { ok, failed };
|
|
695
710
|
}
|
|
696
711
|
|
|
712
|
+
// src/engine/init-project.ts
|
|
713
|
+
import { existsSync as existsSync2, statSync, readdirSync } from "fs";
|
|
714
|
+
import { join as join7 } from "path";
|
|
715
|
+
|
|
716
|
+
// src/migrate/project-docs.ts
|
|
717
|
+
import { basename } from "path";
|
|
718
|
+
var DERIVED = [
|
|
719
|
+
{ re: /^\.horsecode\//, why: "horse-code's own state \u2014 traces describe the code, so rules mined from them would be the code talking back to itself" },
|
|
720
|
+
{ re: /^graphify-out\//, why: "generated by the graph build" },
|
|
721
|
+
{ re: /(^|\/)(node_modules|vendor|third_party|\.git)\//, why: "not this project's writing" },
|
|
722
|
+
{ re: /(^|\/)\.claude\/worktrees\//, why: "a nested checkout of this repository" }
|
|
723
|
+
];
|
|
724
|
+
var HISTORY = [
|
|
725
|
+
{ re: /(^|\/)archive(d)?\//i, why: "an archive of finished work" },
|
|
726
|
+
{ re: /\d{4}-\d{2}-\d{2}/, why: "dated \u2014 a record of a moment, not a standing rule" },
|
|
727
|
+
{ re: /(^|\/)(HANDOFF|RESUME|CHANGELOG|RELEASE[-_]NOTES)[^/]*$/i, why: "a record of what happened" },
|
|
728
|
+
{ re: /(^|\/)chats?\//i, why: "a pasted conversation" },
|
|
729
|
+
{ re: /(^|\/)chat\d*\.md$/i, why: "a pasted conversation" }
|
|
730
|
+
];
|
|
731
|
+
function sortProjectDocs(files, known = []) {
|
|
732
|
+
const seen = new Set(known.map((k) => k.replace(/\\/g, "/")));
|
|
733
|
+
const candidates2 = [];
|
|
734
|
+
const skipped = [];
|
|
735
|
+
for (const f of files) {
|
|
736
|
+
const path = f.path.replace(/\\/g, "/");
|
|
737
|
+
if (!/\.mdx?$/i.test(path)) continue;
|
|
738
|
+
if (seen.has(path) || seen.has(basename(path))) continue;
|
|
739
|
+
const why = DERIVED.find((d) => d.re.test(path))?.why ?? HISTORY.find((h) => h.re.test(path))?.why;
|
|
740
|
+
if (why) skipped.push({ path, bytes: f.bytes, skipped: why });
|
|
741
|
+
else candidates2.push({ path, bytes: f.bytes });
|
|
742
|
+
}
|
|
743
|
+
const bySize = (a, b) => b.bytes - a.bytes;
|
|
744
|
+
return { candidates: candidates2.sort(bySize), skipped: skipped.sort(bySize) };
|
|
745
|
+
}
|
|
746
|
+
function totalBytes(docs) {
|
|
747
|
+
return docs.reduce((n, d) => n + d.bytes, 0);
|
|
748
|
+
}
|
|
749
|
+
function classifyCalls(bytes, chunk) {
|
|
750
|
+
return Math.max(1, Math.ceil(bytes / chunk));
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
// src/engine/init-project.ts
|
|
754
|
+
var UNCLAIMED_FILE_FLOOR = 50;
|
|
755
|
+
function countFiles(dir, cap = UNCLAIMED_FILE_FLOOR * 4) {
|
|
756
|
+
let n = 0;
|
|
757
|
+
const walk = (d) => {
|
|
758
|
+
if (n >= cap) return;
|
|
759
|
+
let entries;
|
|
760
|
+
try {
|
|
761
|
+
entries = readdirSync(d, { withFileTypes: true });
|
|
762
|
+
} catch {
|
|
763
|
+
return;
|
|
764
|
+
}
|
|
765
|
+
for (const e of entries) {
|
|
766
|
+
if (n >= cap) return;
|
|
767
|
+
if (e.isDirectory()) walk(join7(d, e.name));
|
|
768
|
+
else n++;
|
|
769
|
+
}
|
|
770
|
+
};
|
|
771
|
+
walk(dir);
|
|
772
|
+
return n;
|
|
773
|
+
}
|
|
774
|
+
async function initProject(cwd, isIgnored, untracked, knowledge) {
|
|
775
|
+
const changed = await ensureGitignore(cwd);
|
|
776
|
+
const unclaimed = [];
|
|
777
|
+
for (const rel of untracked()) {
|
|
778
|
+
const path = join7(cwd, rel);
|
|
779
|
+
let dir = false;
|
|
780
|
+
try {
|
|
781
|
+
dir = statSync(path).isDirectory();
|
|
782
|
+
} catch {
|
|
783
|
+
continue;
|
|
784
|
+
}
|
|
785
|
+
if (!dir || isIgnored(rel)) continue;
|
|
786
|
+
const files = countFiles(path);
|
|
787
|
+
if (files >= UNCLAIMED_FILE_FLOOR) unclaimed.push({ path: rel, files });
|
|
788
|
+
}
|
|
789
|
+
return {
|
|
790
|
+
changed,
|
|
791
|
+
kept: [`${traceRootRel().replace(/\\/g, "/")}/`, ...sharedDerived()].filter((p) => existsSync2(join7(cwd, p)) || p.endsWith("/")),
|
|
792
|
+
excluded: localOnly(),
|
|
793
|
+
unclaimed: unclaimed.sort((a, b) => b.files - a.files),
|
|
794
|
+
...knowledge ? { knowledge } : {}
|
|
795
|
+
};
|
|
796
|
+
}
|
|
797
|
+
function hasKnowledge(k) {
|
|
798
|
+
return !!k && (k.named.length > 0 || k.docs.length > 0);
|
|
799
|
+
}
|
|
800
|
+
function size(bytes) {
|
|
801
|
+
return bytes >= 1024 * 1024 ? `${(bytes / 1024 / 1024).toFixed(1)} MB` : `${Math.max(1, Math.round(bytes / 1024))} KB`;
|
|
802
|
+
}
|
|
803
|
+
function describeKnowledge(k, chunk = MAX_CHUNK_CHARS) {
|
|
804
|
+
const lines = ["", "**This project already says things about itself.**", ""];
|
|
805
|
+
if (k.named.length) {
|
|
806
|
+
lines.push(`Files a tool is known to write \u2014 ${size(totalBytes(k.named.map((n) => ({ path: n.label, bytes: n.bytes }))))}:`);
|
|
807
|
+
lines.push(...k.named.map((n) => ` \xB7 \`${n.label}\` (${size(n.bytes)})`));
|
|
808
|
+
}
|
|
809
|
+
if (k.docs.length) {
|
|
810
|
+
const bytes = totalBytes(k.docs);
|
|
811
|
+
lines.push("", `The project's other markdown \u2014 ${k.docs.length} file(s), ${size(bytes)}, about ${classifyCalls(bytes, chunk)} classification call(s):`);
|
|
812
|
+
lines.push(...k.docs.slice(0, 8).map((d) => ` \xB7 \`${d.path}\` (${size(d.bytes)})`));
|
|
813
|
+
if (k.docs.length > 8) lines.push(` \xB7 \u2026and ${k.docs.length - 8} more`);
|
|
814
|
+
}
|
|
815
|
+
if (k.skipped.length) {
|
|
816
|
+
const reasons = /* @__PURE__ */ new Map();
|
|
817
|
+
for (const sk of k.skipped) reasons.set(sk.skipped ?? "", (reasons.get(sk.skipped ?? "") ?? 0) + 1);
|
|
818
|
+
lines.push("", `Set aside \u2014 ${k.skipped.length} file(s), ${size(totalBytes(k.skipped))}:`);
|
|
819
|
+
for (const [why, n] of [...reasons].sort((a, b) => b[1] - a[1])) lines.push(` \xB7 ${n} \xD7 ${why}`);
|
|
820
|
+
}
|
|
821
|
+
return lines.join("\n");
|
|
822
|
+
}
|
|
823
|
+
function describeInit(report) {
|
|
824
|
+
const lines = [
|
|
825
|
+
report.changed ? "**Project set up for horse-code** \u2014 `.gitignore` updated." : "**Project is already set up** \u2014 `.gitignore` already says everything needed.",
|
|
826
|
+
"",
|
|
827
|
+
"Committed on purpose, because a clone would otherwise pay to produce it again:",
|
|
828
|
+
...report.kept.map((p) => ` \xB7 \`${p}\``),
|
|
829
|
+
"",
|
|
830
|
+
"Kept out on purpose \u2014 derived from the source, keyed to this checkout, or unmergeable:",
|
|
831
|
+
...report.excluded.map((p) => ` \xB7 \`${p}\``)
|
|
832
|
+
];
|
|
833
|
+
if (report.unclaimed.length) {
|
|
834
|
+
lines.push(
|
|
835
|
+
"",
|
|
836
|
+
"Untracked and covered by no rule \u2014 `git add -A` would commit these. Yours to decide:",
|
|
837
|
+
...report.unclaimed.map((u) => ` \xB7 \`${u.path}\` (${u.files >= UNCLAIMED_FILE_FLOOR * 4 ? `${u.files}+` : u.files} files)`)
|
|
838
|
+
);
|
|
839
|
+
}
|
|
840
|
+
return lines.join("\n");
|
|
841
|
+
}
|
|
842
|
+
|
|
697
843
|
// src/permission/rules.ts
|
|
698
844
|
import picomatch from "picomatch";
|
|
699
845
|
var DANGEROUS_PATTERNS = [
|
|
@@ -964,8 +1110,8 @@ var ProposalQueue = class {
|
|
|
964
1110
|
};
|
|
965
1111
|
|
|
966
1112
|
// src/speckit/templates.ts
|
|
967
|
-
import { existsSync as
|
|
968
|
-
import { join as
|
|
1113
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
1114
|
+
import { join as join8, dirname as dirname3 } from "path";
|
|
969
1115
|
var TEMPLATE_FILES = {
|
|
970
1116
|
spec: "spec-template.md",
|
|
971
1117
|
plan: "plan-template.md",
|
|
@@ -988,10 +1134,10 @@ async function loadSpecKit(opts) {
|
|
|
988
1134
|
);
|
|
989
1135
|
}
|
|
990
1136
|
const fetchFn = opts.fetch ?? globalThis.fetch;
|
|
991
|
-
const cacheDir =
|
|
1137
|
+
const cacheDir = join8(opts.home, ".horsecode", "spec-kit", opts.version, "templates");
|
|
992
1138
|
const get = async (relPath) => {
|
|
993
|
-
const cachePath =
|
|
994
|
-
if (
|
|
1139
|
+
const cachePath = join8(cacheDir, relPath);
|
|
1140
|
+
if (existsSync3(cachePath)) return readFileSync3(cachePath, "utf8");
|
|
995
1141
|
const url = `${RAW_BASE}/${opts.version}/templates/${relPath}`;
|
|
996
1142
|
const res = await fetchFn(url);
|
|
997
1143
|
if (!res.ok) {
|
|
@@ -1018,7 +1164,7 @@ Check your network or set specKit.version to a valid tag.`
|
|
|
1018
1164
|
|
|
1019
1165
|
// src/wiring.ts
|
|
1020
1166
|
import { homedir } from "os";
|
|
1021
|
-
import { join as
|
|
1167
|
+
import { join as join9 } from "path";
|
|
1022
1168
|
async function buildJobDeps(opts) {
|
|
1023
1169
|
const { config } = opts;
|
|
1024
1170
|
const roles = {};
|
|
@@ -1064,7 +1210,7 @@ async function buildJobDeps(opts) {
|
|
|
1064
1210
|
const queue = new ProposalQueue();
|
|
1065
1211
|
let kitPromise;
|
|
1066
1212
|
const specKit = () => kitPromise ??= loadSpecKit({ version: config.specKit.version, home: opts.home, fetch: opts.fetch });
|
|
1067
|
-
const fitness = new RoleFitness(
|
|
1213
|
+
const fitness = new RoleFitness(join9(opts.home ?? homedir(), ".horsecode", "model-fitness.json"));
|
|
1068
1214
|
roleRegistry.setFitness(fitness);
|
|
1069
1215
|
return {
|
|
1070
1216
|
provider: opts.provider,
|
|
@@ -1257,9 +1403,9 @@ function redactRecord(record) {
|
|
|
1257
1403
|
|
|
1258
1404
|
// src/obs/sink.ts
|
|
1259
1405
|
import { createWriteStream, mkdirSync as mkdirSync4 } from "fs";
|
|
1260
|
-
import { join as
|
|
1406
|
+
import { join as join10 } from "path";
|
|
1261
1407
|
function telemetryDir(home) {
|
|
1262
|
-
return
|
|
1408
|
+
return join10(home, ".horsecode", "telemetry");
|
|
1263
1409
|
}
|
|
1264
1410
|
var MAX_QUEUE = 1e4;
|
|
1265
1411
|
var FileSink = class {
|
|
@@ -1268,7 +1414,7 @@ var FileSink = class {
|
|
|
1268
1414
|
dropped = 0;
|
|
1269
1415
|
path;
|
|
1270
1416
|
constructor(home, runId) {
|
|
1271
|
-
this.path =
|
|
1417
|
+
this.path = join10(telemetryDir(home), `${runId}.jsonl`);
|
|
1272
1418
|
try {
|
|
1273
1419
|
mkdirSync4(telemetryDir(home), { recursive: true });
|
|
1274
1420
|
this.stream = createWriteStream(this.path, { flags: "a" });
|
|
@@ -1328,12 +1474,12 @@ var FileSink = class {
|
|
|
1328
1474
|
|
|
1329
1475
|
// src/cli-info.ts
|
|
1330
1476
|
import { readFileSync as readFileSync4 } from "fs";
|
|
1331
|
-
import { dirname as dirname4, join as
|
|
1477
|
+
import { dirname as dirname4, join as join11 } from "path";
|
|
1332
1478
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
1333
1479
|
function hcodeVersion() {
|
|
1334
1480
|
try {
|
|
1335
1481
|
const here = dirname4(fileURLToPath2(import.meta.url));
|
|
1336
|
-
const pkg = JSON.parse(readFileSync4(
|
|
1482
|
+
const pkg = JSON.parse(readFileSync4(join11(here, "..", "package.json"), "utf8"));
|
|
1337
1483
|
return pkg.version ?? "unknown";
|
|
1338
1484
|
} catch {
|
|
1339
1485
|
return "unknown";
|
|
@@ -1499,6 +1645,7 @@ function renderResult(res) {
|
|
|
1499
1645
|
if (res.kind === "rejected") return `Not approved (stopped at the ${res.stage} stage).`;
|
|
1500
1646
|
if (res.kind === "undone") return res.report;
|
|
1501
1647
|
if (res.kind === "verified") return res.report;
|
|
1648
|
+
if (res.kind === "researched") return res.report;
|
|
1502
1649
|
if (res.kind === "tweaked") return res.report;
|
|
1503
1650
|
if (res.kind === "governed") {
|
|
1504
1651
|
return res.written ? `**Constitution written** \u2014 \`${res.path}\`
|
|
@@ -1719,14 +1866,43 @@ async function main(argv) {
|
|
|
1719
1866
|
);
|
|
1720
1867
|
const notSignedIn = ambientLogins.filter((a) => !a.status.loggedIn).map((a) => a.kind);
|
|
1721
1868
|
const accountsNote = () => accountsLine(accounts.usage(), notSignedIn);
|
|
1869
|
+
const initProjectFn = async () => {
|
|
1870
|
+
const r = await defaultGitRunner(["ls-files", "--others", "--exclude-standard", "--directory"], cwd);
|
|
1871
|
+
const list = r.stdout.split("\n").map((l) => l.trim()).filter(Boolean);
|
|
1872
|
+
const ignored = /* @__PURE__ */ new Set();
|
|
1873
|
+
for (const path of list) {
|
|
1874
|
+
if ((await defaultGitRunner(["check-ignore", "-q", path], cwd)).code === 0) ignored.add(path);
|
|
1875
|
+
}
|
|
1876
|
+
const all = await defaultGitRunner(["ls-files", "--cached", "--others", "--exclude-standard"], cwd);
|
|
1877
|
+
const md = all.stdout.split("\n").map((l) => l.trim()).filter((l) => /\.mdx?$/i.test(l));
|
|
1878
|
+
const withSize = md.map((path) => {
|
|
1879
|
+
try {
|
|
1880
|
+
return { path, bytes: statSync2(join12(cwd, path)).size };
|
|
1881
|
+
} catch {
|
|
1882
|
+
return { path, bytes: 0 };
|
|
1883
|
+
}
|
|
1884
|
+
});
|
|
1885
|
+
const found = await discover({ cwd, home });
|
|
1886
|
+
const named = found.filter((f) => f.kind === "rules" || f.kind === "mcp").map((f) => ({ label: f.label, bytes: f.bytes }));
|
|
1887
|
+
const { candidates: candidates2, skipped } = sortProjectDocs(withSize, found.map((f) => f.label));
|
|
1888
|
+
const knowledge = { named, docs: candidates2, skipped };
|
|
1889
|
+
const report = await initProject(cwd, (path) => ignored.has(path), () => list, knowledge);
|
|
1890
|
+
const canImport = hasKnowledge(knowledge);
|
|
1891
|
+
const extra = [];
|
|
1892
|
+
for (const d of candidates2) {
|
|
1893
|
+
const r2 = await readFinding(join12(cwd, d.path));
|
|
1894
|
+
if (r2?.text) extra.push({ kind: "rules", tool: "project document", path: join12(cwd, d.path), label: d.path, bytes: r2.bytes, own: true, text: r2.text });
|
|
1895
|
+
}
|
|
1896
|
+
return { text: describeInit(report) + (canImport ? describeKnowledge(knowledge) : ""), canImport, extra };
|
|
1897
|
+
};
|
|
1722
1898
|
const modelsPanelNote = (inUse) => modelsPanel(accounts.usage(), modelsFor, CLI_KINDS, inUse);
|
|
1723
1899
|
const raw = new CliProvider({ readOnly: false, accounts });
|
|
1724
1900
|
const provider = config.telemetry ? telemetryProvider(raw, telemetry()) : raw;
|
|
1725
1901
|
const skillRegistry = new SkillRegistry();
|
|
1726
1902
|
await registerBuiltinSkills(skillRegistry);
|
|
1727
1903
|
await skillRegistry.loadFromDir(externalSkillsDir(home));
|
|
1728
|
-
const skillsDir =
|
|
1729
|
-
if (
|
|
1904
|
+
const skillsDir = join12(cwd, ".horsecode", "skills");
|
|
1905
|
+
if (existsSync4(skillsDir)) await skillRegistry.loadFromDir(skillsDir);
|
|
1730
1906
|
const worktreeHome = await mainWorktreeRoot(defaultGitRunner, cwd);
|
|
1731
1907
|
if (worktreeHome !== cwd) {
|
|
1732
1908
|
console.log(`\u2139\uFE0F Sessions will be opened in ${worktreeHome} \u2014 the repository's main checkout.`);
|
|
@@ -1758,7 +1934,7 @@ async function main(argv) {
|
|
|
1758
1934
|
const useTui = shouldUseTui(!!process.stdin.isTTY, !!process.stdout.isTTY, !!args.noTui);
|
|
1759
1935
|
if (!args.prompt) {
|
|
1760
1936
|
if (useTui) {
|
|
1761
|
-
const { runTuiRepl } = await import("./app-
|
|
1937
|
+
const { runTuiRepl } = await import("./app-KR7TAHUD.js");
|
|
1762
1938
|
const { fetchCatalog, makeProbe, discoverSources } = await import("./discover-G2Z6XC3O.js");
|
|
1763
1939
|
const { loadSourceCache, saveSourceCache } = await import("./source-cache-XEK5WN7I.js");
|
|
1764
1940
|
const manualSources = config.modelSources.length > 0;
|
|
@@ -1809,8 +1985,8 @@ _Expected something like \`https://github.com/owner/repo\` or a link to the dire
|
|
|
1809
1985
|
_Discoverable by every agent. \`/roles adjust\` assigns it to the roles it fits; \`/skills update\` re-installs it from upstream._`;
|
|
1810
1986
|
};
|
|
1811
1987
|
const reloadProjectSkills = async () => {
|
|
1812
|
-
const dir =
|
|
1813
|
-
if (
|
|
1988
|
+
const dir = join12(cwd, ".horsecode", "skills");
|
|
1989
|
+
if (existsSync4(dir)) await skillRegistry.loadFromDir(dir);
|
|
1814
1990
|
};
|
|
1815
1991
|
const updateSkills = async () => {
|
|
1816
1992
|
if (!config.skillSources.length) {
|
|
@@ -1829,7 +2005,7 @@ _Discoverable by every agent. \`/roles adjust\` assigns it to the roles it fits;
|
|
|
1829
2005
|
${lines.join("\n")}${tail}`;
|
|
1830
2006
|
};
|
|
1831
2007
|
const graphStatusText = async () => {
|
|
1832
|
-
const st = await graphStatus(
|
|
2008
|
+
const st = await graphStatus((await derivedWorkdir(false)).dir);
|
|
1833
2009
|
if (!st.built) {
|
|
1834
2010
|
const py = await graphifyPython();
|
|
1835
2011
|
return py ? "No code graph yet. `/graph build` \u2014 AST parsing only, no tokens, a few seconds.\n\n_Without it every agent works blind: it can grep for a name but cannot tell what calls it._" : "No code graph, and graphify is not installed.\n\n`uv tool install graphifyy` (or `pipx install graphifyy`), then `/graph build`.\n\n_MIT, pure tree-sitter AST parsing \u2014 no API key, no tokens._";
|
|
@@ -1848,7 +2024,7 @@ ${lines.join("\n")}${tail}`;
|
|
|
1848
2024
|
|
|
1849
2025
|
_Every agent can query it: \`graph_impact\` (blast radius), \`graph_trace\`, \`graph_find\`, \`graph_context\`, \`graph_overview\`._`;
|
|
1850
2026
|
};
|
|
1851
|
-
const buildGraphText = async () => (await buildProjectGraph(
|
|
2027
|
+
const buildGraphText = async () => (await buildProjectGraph((await derivedWorkdir(true)).dir)).message;
|
|
1852
2028
|
const cleanWorktreesText = async (apply, branch) => {
|
|
1853
2029
|
const { surveySessions, cleanSessions, describeSurvey, describeClean } = await import("./clean-YOQATBMZ.js");
|
|
1854
2030
|
const target = branch?.trim() || fromBranch;
|
|
@@ -1858,31 +2034,42 @@ _Every agent can query it: \`graph_impact\` (blast radius), \`graph_trace\`, \`g
|
|
|
1858
2034
|
return describeClean(await cleanSessions(defaultGitRunner, cwd, target), target);
|
|
1859
2035
|
};
|
|
1860
2036
|
const gitFiles = async () => (await defaultGitRunner(["ls-files", "--cached", "--others", "--exclude-standard"], cwd)).stdout.split("\n").filter(Boolean);
|
|
1861
|
-
const traceableDocs = async () => traceableFiles(
|
|
1862
|
-
const traceableFiles2 = async () => traceableFiles(
|
|
1863
|
-
const
|
|
2037
|
+
const traceableDocs = async (dir = cwd) => traceableFiles(dir, { code: false });
|
|
2038
|
+
const traceableFiles2 = async (dir = cwd) => traceableFiles(dir);
|
|
2039
|
+
const tracerChain = () => {
|
|
1864
2040
|
for (const role of ["tracer", "architect", "senior-coder", "judge"]) {
|
|
1865
|
-
const
|
|
1866
|
-
if (
|
|
2041
|
+
const chain = (config.roles[role]?.models ?? []).filter((m) => m && m !== "default");
|
|
2042
|
+
if (chain.length) return chain;
|
|
1867
2043
|
}
|
|
1868
|
-
return config.model;
|
|
2044
|
+
return [config.model];
|
|
2045
|
+
};
|
|
2046
|
+
const derivedWorkdir = async (create) => {
|
|
2047
|
+
const inSession = sessionBase(cwd);
|
|
2048
|
+
if (inSession) return { dir: inSession };
|
|
2049
|
+
const standing = join12(cwd, ".horsecode", "worktrees", "traces", "base");
|
|
2050
|
+
if (!create) return { dir: existsSync4(standing) ? standing : cwd };
|
|
2051
|
+
const session = await manager.openFixed(fromBranch, "traces");
|
|
2052
|
+
return { dir: session.baseWorktree, session };
|
|
1869
2053
|
};
|
|
1870
2054
|
const planTracesFn = async () => {
|
|
1871
|
-
const
|
|
1872
|
-
|
|
2055
|
+
const { dir } = await derivedWorkdir(false);
|
|
2056
|
+
const plan = await planFor(dir, await traceableFiles2(dir));
|
|
2057
|
+
return { summary: describePlan(plan, tracerChain()), jobs: plan.jobs.length };
|
|
1873
2058
|
};
|
|
1874
2059
|
const runTracesFn = async (onProgress, metered) => {
|
|
1875
|
-
const
|
|
1876
|
-
const
|
|
1877
|
-
const
|
|
2060
|
+
const { dir, session } = await derivedWorkdir(true);
|
|
2061
|
+
const files = await traceableFiles2(dir);
|
|
2062
|
+
const brief = await buildBrief({ cwd: dir, provider: metered ?? provider, models: tracerChain(), files: await traceableDocs(dir) });
|
|
2063
|
+
const plan = await planFor(dir, files);
|
|
1878
2064
|
const res = await runTraces({
|
|
1879
|
-
cwd,
|
|
2065
|
+
cwd: dir,
|
|
1880
2066
|
provider: metered ?? provider,
|
|
1881
|
-
|
|
2067
|
+
models: tracerChain(),
|
|
1882
2068
|
plan,
|
|
1883
2069
|
liveFiles: new Set(files),
|
|
1884
2070
|
...onProgress ? { onProgress } : {}
|
|
1885
2071
|
});
|
|
2072
|
+
if (session) await manager.preserveSession(session, `docs(traces): ${res.written} file(s) described`);
|
|
1886
2073
|
const bits = [`${brief.message}
|
|
1887
2074
|
|
|
1888
2075
|
**Traces written: ${res.written}**`];
|
|
@@ -1890,9 +2077,13 @@ _Every agent can query it: \`graph_impact\` (blast radius), \`graph_trace\`, \`g
|
|
|
1890
2077
|
if (res.pruned.length) bits.push(`${res.pruned.length} removed for deleted files`);
|
|
1891
2078
|
if (res.wroteGitignore) bits.push("\n\n_Added .gitignore rules: traces are committed, the AST cache is not._");
|
|
1892
2079
|
const failures = describeTraceFailures(res.failed);
|
|
2080
|
+
const landed = session ? `
|
|
2081
|
+
|
|
2082
|
+
_Written and committed on \`${session.baseBranch}\`, so your working tree is untouched._
|
|
2083
|
+
_Bring them in with \`git merge ${session.baseBranch}\`, or browse them at \`${session.baseWorktree}\`._` : "\n\n_Written in this session's worktree, on its own branch._";
|
|
1893
2084
|
return `${bits.join(" \xB7 ")}${failures ? `
|
|
1894
2085
|
|
|
1895
|
-
${failures}` : ""}
|
|
2086
|
+
${failures}` : ""}${landed}
|
|
1896
2087
|
|
|
1897
2088
|
_Committed with the repo, so every clone starts with them. Agents read one with \`graph_trace\`._`;
|
|
1898
2089
|
};
|
|
@@ -1901,11 +2092,13 @@ _Committed with the repo, so every clone starts with them. Agents read one with
|
|
|
1901
2092
|
memStore,
|
|
1902
2093
|
accountsNote,
|
|
1903
2094
|
modelsPanel: modelsPanelNote,
|
|
2095
|
+
initProject: initProjectFn,
|
|
1904
2096
|
listSkills,
|
|
1905
2097
|
updateSkills,
|
|
1906
2098
|
addSkill,
|
|
1907
2099
|
reloadProjectSkills,
|
|
1908
2100
|
graphStatus: graphStatusText,
|
|
2101
|
+
derivedDir: async () => (await derivedWorkdir(true)).dir,
|
|
1909
2102
|
buildGraph: buildGraphText,
|
|
1910
2103
|
cleanWorktrees: cleanWorktreesText,
|
|
1911
2104
|
planTraces: planTracesFn,
|
|
@@ -1938,7 +2131,7 @@ _Committed with the repo, so every clone starts with them. Agents read one with
|
|
|
1938
2131
|
...args.revisionRounds !== void 0 && { revisionRounds: args.revisionRounds }
|
|
1939
2132
|
};
|
|
1940
2133
|
if (useTui) {
|
|
1941
|
-
const { runTui } = await import("./app-
|
|
2134
|
+
const { runTui } = await import("./app-KR7TAHUD.js");
|
|
1942
2135
|
const res = await runTui({ buildDeps, job });
|
|
1943
2136
|
console.log(renderResult(res));
|
|
1944
2137
|
return;
|
|
@@ -8,18 +8,21 @@ import {
|
|
|
8
8
|
dirtyPaths,
|
|
9
9
|
runFix,
|
|
10
10
|
runSmallChange
|
|
11
|
-
} from "./chunk-
|
|
12
|
-
import "./chunk-
|
|
11
|
+
} from "./chunk-UANNVVIU.js";
|
|
12
|
+
import "./chunk-PIG54WFU.js";
|
|
13
|
+
import "./chunk-NBTH2VVI.js";
|
|
13
14
|
import "./chunk-ZSQ24YDJ.js";
|
|
15
|
+
import "./chunk-ACTVFJRW.js";
|
|
16
|
+
import "./chunk-MZM24M5M.js";
|
|
14
17
|
import "./chunk-G45RWL7S.js";
|
|
15
|
-
import "./chunk-MRZVA5JB.js";
|
|
16
18
|
import "./chunk-LPQU436C.js";
|
|
17
|
-
import "./chunk-
|
|
19
|
+
import "./chunk-BFIZMM4G.js";
|
|
20
|
+
import "./chunk-CYLPQWIF.js";
|
|
18
21
|
import "./chunk-63E73TGI.js";
|
|
19
|
-
import "./chunk-
|
|
20
|
-
import "./chunk-
|
|
21
|
-
import "./chunk-
|
|
22
|
-
import "./chunk-
|
|
22
|
+
import "./chunk-6S4WWQMN.js";
|
|
23
|
+
import "./chunk-JLWQCA7B.js";
|
|
24
|
+
import "./chunk-ZPJP2VH5.js";
|
|
25
|
+
import "./chunk-4M6LXNG2.js";
|
|
23
26
|
import "./chunk-6W4UH2BQ.js";
|
|
24
27
|
export {
|
|
25
28
|
FIX_ATTEMPTS,
|
|
@@ -3,12 +3,13 @@ import {
|
|
|
3
3
|
} from "./chunk-YBWTCXUS.js";
|
|
4
4
|
import {
|
|
5
5
|
askInUserLanguage
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-UTHLEW5V.js";
|
|
7
7
|
import {
|
|
8
8
|
checkpointMtime,
|
|
9
9
|
readCheckpoint
|
|
10
10
|
} from "./chunk-ZSQ24YDJ.js";
|
|
11
|
-
import "./chunk-
|
|
11
|
+
import "./chunk-CYLPQWIF.js";
|
|
12
|
+
import "./chunk-JLWQCA7B.js";
|
|
12
13
|
import "./chunk-6W4UH2BQ.js";
|
|
13
14
|
|
|
14
15
|
// src/engine/ongoing.ts
|