@open-tomato/rafa 0.40.0 → 0.42.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/README.md +6 -1
- package/dist/cli.js +26005 -27854
- package/dist/continue-criteria.md +31 -0
- package/dist/continue-decision-prompt.md +94 -0
- package/dist/effort/store/index.js +4 -6
- package/dist/{index-krpmxpkh.js → index-7ycam8pq.js} +31 -18
- package/dist/{index-334y39tn.js → index-bceachy6.js} +509 -51
- package/dist/{index-wp8c28fd.js → index-hf2k497d.js} +1 -3
- package/dist/{index-d6d0942q.js → index-nv34ptht.js} +1 -1
- package/dist/{index-8veaj0t9.js → index-q0dmfp8m.js} +180 -254
- package/dist/index.js +30751 -32
- package/dist/learning/index.js +2 -2
- package/dist/plan/index.js +4 -6
- package/package.json +2 -2
- package/dist/describe-pwhh0vws.js +0 -14
- package/dist/index-eyjq63mx.js +0 -243
- package/dist/index-j7kjj0dd.js +0 -27902
- package/dist/index-m2ahxjw8.js +0 -450
- package/dist/index-sr3kc4mf.js +0 -129
- package/dist/index-zcbj07aq.js +0 -34704
|
@@ -1,49 +1,43 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import {
|
|
3
|
+
BUSY_TIMEOUT_MAX_MS,
|
|
4
|
+
BUSY_TIMEOUT_MIN_MS,
|
|
3
5
|
CONFIG_DEFAULTS,
|
|
4
6
|
CONFIG_FILE,
|
|
5
7
|
ConfigError,
|
|
6
8
|
FINDING_DOMAINS,
|
|
7
9
|
FINDING_KINDS,
|
|
8
10
|
FINDING_SIGNALS,
|
|
9
|
-
activeOutput,
|
|
10
|
-
activeOutputMode,
|
|
11
|
-
configFilePath,
|
|
12
|
-
createTextOutput,
|
|
13
|
-
hubContextOf,
|
|
14
|
-
isStampableStub,
|
|
15
|
-
parseConfigText,
|
|
16
|
-
readRafaBlocks,
|
|
17
|
-
resolveConfig
|
|
18
|
-
} from "./index-334y39tn.js";
|
|
19
|
-
import {
|
|
20
|
-
bless,
|
|
21
|
-
merge
|
|
22
|
-
} from "./index-d6d0942q.js";
|
|
23
|
-
import {
|
|
24
|
-
CommandExit,
|
|
25
|
-
commandSpelling
|
|
26
|
-
} from "./index-sr3kc4mf.js";
|
|
27
|
-
import {
|
|
28
|
-
BUSY_TIMEOUT_MAX_MS,
|
|
29
|
-
BUSY_TIMEOUT_MIN_MS,
|
|
30
11
|
RAFA_INSTINCTS_PATH,
|
|
31
12
|
STORE_BACKENDS,
|
|
32
13
|
SYNC_STRATEGIES,
|
|
33
14
|
TEST_SCOPES,
|
|
15
|
+
activeOutput,
|
|
16
|
+
activeOutputMode,
|
|
34
17
|
bundledBinDirectory,
|
|
18
|
+
configFilePath,
|
|
19
|
+
createTextOutput,
|
|
35
20
|
describeValue,
|
|
21
|
+
hubContextOf,
|
|
36
22
|
isBusyTimeoutMs,
|
|
37
23
|
isGitHubLogin,
|
|
38
24
|
isMapping,
|
|
25
|
+
isStampableStub,
|
|
39
26
|
messageOf,
|
|
27
|
+
parseConfigText,
|
|
28
|
+
readRafaBlocks,
|
|
29
|
+
resolveConfig,
|
|
40
30
|
resolveInstinctScopes,
|
|
41
31
|
tierExists
|
|
42
|
-
} from "./index-
|
|
32
|
+
} from "./index-bceachy6.js";
|
|
33
|
+
import {
|
|
34
|
+
bless,
|
|
35
|
+
merge
|
|
36
|
+
} from "./index-nv34ptht.js";
|
|
43
37
|
import {
|
|
44
38
|
actionHash,
|
|
45
39
|
triggerKey
|
|
46
|
-
} from "./index-
|
|
40
|
+
} from "./index-hf2k497d.js";
|
|
47
41
|
|
|
48
42
|
// src/adapters/registry.ts
|
|
49
43
|
import { homedir } from "os";
|
|
@@ -259,13 +253,10 @@ import { Database as Database2 } from "bun:sqlite";
|
|
|
259
253
|
|
|
260
254
|
// package.json
|
|
261
255
|
var name = "@open-tomato/rafa";
|
|
262
|
-
var version = "0.
|
|
256
|
+
var version = "0.42.0";
|
|
263
257
|
|
|
264
258
|
// src/cli/version.ts
|
|
265
259
|
var RAFA_VERSION = version;
|
|
266
|
-
function versionLine() {
|
|
267
|
-
return `rafa ${RAFA_VERSION}`;
|
|
268
|
-
}
|
|
269
260
|
|
|
270
261
|
// src/effort/store/development-build.ts
|
|
271
262
|
import { tmpdir as tmpdir2 } from "os";
|
|
@@ -535,12 +526,6 @@ function writePositionFile(root, position) {
|
|
|
535
526
|
function positionAt(place) {
|
|
536
527
|
return { current: place, previous: null, home: place };
|
|
537
528
|
}
|
|
538
|
-
function rehome(position, place) {
|
|
539
|
-
return { current: place, previous: position.current, home: place };
|
|
540
|
-
}
|
|
541
|
-
function hop(position, place) {
|
|
542
|
-
return { current: place, previous: position.current, home: position.home };
|
|
543
|
-
}
|
|
544
529
|
function goHome(position) {
|
|
545
530
|
return { current: position.home, previous: position.current, home: position.home };
|
|
546
531
|
}
|
|
@@ -652,11 +637,11 @@ function staleAgainst(record, position) {
|
|
|
652
637
|
// src/loop/session-record-parse.ts
|
|
653
638
|
var SESSION_STATES = Object.freeze(["running", "paused", "stopped", "done"]);
|
|
654
639
|
var SESSION_PHASES = Object.freeze(["task", "wrap-up", "pull-request", "ci", "repair"]);
|
|
655
|
-
var DEFAULT_PHASE = "task";
|
|
656
640
|
var RECORD_EXTENSION = ".json";
|
|
657
641
|
var SESSION_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
|
|
658
642
|
var SESSION_STEP_KINDS = Object.freeze(["baseline", "task", "stage", "pre-wrap-up"]);
|
|
659
643
|
var SESSION_STEP_REASONS = Object.freeze(["declared", "trigger", "fallback", "no-module-tests", "stage"]);
|
|
644
|
+
var SESSION_DECISION_STRATEGIES = Object.freeze(["jump", "defer"]);
|
|
660
645
|
|
|
661
646
|
class SessionRecordError extends Error {
|
|
662
647
|
file;
|
|
@@ -697,8 +682,8 @@ function taskProblem(task) {
|
|
|
697
682
|
function hopProblem(fields) {
|
|
698
683
|
if (!Object.hasOwn(fields, "hop"))
|
|
699
684
|
return null;
|
|
700
|
-
const
|
|
701
|
-
return asHopRecord(
|
|
685
|
+
const hop = field(fields, "hop");
|
|
686
|
+
return asHopRecord(hop) === null ? `hop is ${describeValue2(hop)}, expected a hop record` : null;
|
|
702
687
|
}
|
|
703
688
|
function worktreeProblem(fields) {
|
|
704
689
|
if (!Object.hasOwn(fields, "worktree"))
|
|
@@ -755,6 +740,49 @@ function stepProblems(step, at) {
|
|
|
755
740
|
];
|
|
756
741
|
return problems.filter((problem) => problem !== null);
|
|
757
742
|
}
|
|
743
|
+
function isLineIndex(value) {
|
|
744
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
745
|
+
}
|
|
746
|
+
function taskRefProblems(ref, at) {
|
|
747
|
+
if (!isObject(ref))
|
|
748
|
+
return [`${at} is ${describeValue2(ref)}, expected a task`];
|
|
749
|
+
const lineNum = field(ref, "lineNum");
|
|
750
|
+
const task = field(ref, "task");
|
|
751
|
+
const ordinal = field(ref, "ordinal");
|
|
752
|
+
return [
|
|
753
|
+
isLineIndex(lineNum) ? null : `${at}.lineNum is ${describeValue2(lineNum)}, expected a whole number from 0`,
|
|
754
|
+
isText(task) ? null : `${at}.task is ${describeValue2(task)}, expected a non-empty string`,
|
|
755
|
+
ordinal === undefined || isPositiveWhole(ordinal) ? null : `${at}.ordinal is ${describeValue2(ordinal)}, expected a whole number from 1`
|
|
756
|
+
].filter((problem) => problem !== null);
|
|
757
|
+
}
|
|
758
|
+
function afterProblems(decision, strategy, at) {
|
|
759
|
+
const after = field(decision, "after");
|
|
760
|
+
if (strategy === "defer") {
|
|
761
|
+
return after === undefined ? [`${at}.after is missing, expected the task a defer waits on`] : taskRefProblems(after, `${at}.after`);
|
|
762
|
+
}
|
|
763
|
+
return after === undefined ? [] : [`${at}.after is ${describeValue2(after)}, expected no key on a jump`];
|
|
764
|
+
}
|
|
765
|
+
function decisionProblems(decision, at) {
|
|
766
|
+
if (!isObject(decision))
|
|
767
|
+
return [`${at} is ${describeValue2(decision)}, expected a decision`];
|
|
768
|
+
const strategy = field(decision, "strategy");
|
|
769
|
+
const reason = field(decision, "reason");
|
|
770
|
+
const problems = [
|
|
771
|
+
...taskRefProblems(field(decision, "task"), `${at}.task`),
|
|
772
|
+
SESSION_DECISION_STRATEGIES.includes(strategy) ? null : `${at}.strategy is ${describeValue2(strategy)}, expected one of ${SESSION_DECISION_STRATEGIES.join(", ")}`,
|
|
773
|
+
isText(reason) ? null : `${at}.reason is ${describeValue2(reason)}, expected a non-empty string`,
|
|
774
|
+
...afterProblems(decision, strategy, at)
|
|
775
|
+
];
|
|
776
|
+
return problems.filter((problem) => problem !== null);
|
|
777
|
+
}
|
|
778
|
+
function decisionsProblems(fields) {
|
|
779
|
+
if (!Object.hasOwn(fields, "decisions"))
|
|
780
|
+
return [];
|
|
781
|
+
const decisions = field(fields, "decisions");
|
|
782
|
+
if (!Array.isArray(decisions))
|
|
783
|
+
return [`decisions is ${describeValue2(decisions)}, expected a list of decisions`];
|
|
784
|
+
return decisions.flatMap((decision, index) => decisionProblems(decision, `decisions[${index}]`));
|
|
785
|
+
}
|
|
758
786
|
function stepsProblems(fields) {
|
|
759
787
|
if (!Object.hasOwn(fields, "steps"))
|
|
760
788
|
return [];
|
|
@@ -789,7 +817,8 @@ function recordProblems(fields, file) {
|
|
|
789
817
|
taskProblem(field(fields, "task")),
|
|
790
818
|
hopProblem(fields),
|
|
791
819
|
worktreeProblem(fields),
|
|
792
|
-
...stepsProblems(fields)
|
|
820
|
+
...stepsProblems(fields),
|
|
821
|
+
...decisionsProblems(fields)
|
|
793
822
|
];
|
|
794
823
|
return problems.filter((problem) => problem !== null);
|
|
795
824
|
}
|
|
@@ -800,8 +829,8 @@ function phaseEntry(phase) {
|
|
|
800
829
|
return isSessionPhase(phase) ? { phase } : {};
|
|
801
830
|
}
|
|
802
831
|
function freezeHop(value) {
|
|
803
|
-
const
|
|
804
|
-
return Object.freeze({ ...
|
|
832
|
+
const hop = asHopRecord(value);
|
|
833
|
+
return Object.freeze({ ...hop, home: Object.freeze(hop.home), from: Object.freeze(hop.from) });
|
|
805
834
|
}
|
|
806
835
|
function freezeFailures(failures) {
|
|
807
836
|
return Object.freeze(failures.map((failure) => Object.freeze({ file: failure.file, name: failure.name })));
|
|
@@ -830,9 +859,29 @@ function stepsEntry(steps) {
|
|
|
830
859
|
return {};
|
|
831
860
|
return { steps: Object.freeze(steps.map(freezeStep)) };
|
|
832
861
|
}
|
|
862
|
+
function freezeTaskRef(ref) {
|
|
863
|
+
return Object.freeze({
|
|
864
|
+
lineNum: ref.lineNum,
|
|
865
|
+
task: ref.task,
|
|
866
|
+
...ref.ordinal === undefined ? {} : { ordinal: ref.ordinal }
|
|
867
|
+
});
|
|
868
|
+
}
|
|
869
|
+
function freezeDecision(decision) {
|
|
870
|
+
return Object.freeze({
|
|
871
|
+
task: freezeTaskRef(decision.task),
|
|
872
|
+
strategy: decision.strategy,
|
|
873
|
+
reason: decision.reason,
|
|
874
|
+
...decision.after === undefined ? {} : { after: freezeTaskRef(decision.after) }
|
|
875
|
+
});
|
|
876
|
+
}
|
|
877
|
+
function decisionsEntry(decisions) {
|
|
878
|
+
if (!Array.isArray(decisions) || decisions.length === 0)
|
|
879
|
+
return {};
|
|
880
|
+
return { decisions: Object.freeze(decisions.map(freezeDecision)) };
|
|
881
|
+
}
|
|
833
882
|
function freezeRecord(fields) {
|
|
834
883
|
const task = field(fields, "task");
|
|
835
|
-
const
|
|
884
|
+
const hop = field(fields, "hop");
|
|
836
885
|
const worktree = field(fields, "worktree");
|
|
837
886
|
return Object.freeze({
|
|
838
887
|
sessionId: field(fields, "sessionId"),
|
|
@@ -844,16 +893,17 @@ function freezeRecord(fields) {
|
|
|
844
893
|
state: field(fields, "state"),
|
|
845
894
|
task: isObject(task) ? Object.freeze({ line: field(task, "line"), text: field(task, "text") }) : null,
|
|
846
895
|
...phaseEntry(field(fields, "phase")),
|
|
847
|
-
...
|
|
896
|
+
...hop === undefined ? {} : { hop: freezeHop(hop) },
|
|
848
897
|
...worktree === undefined ? {} : { worktree },
|
|
849
|
-
...stepsEntry(field(fields, "steps"))
|
|
898
|
+
...stepsEntry(field(fields, "steps")),
|
|
899
|
+
...decisionsEntry(field(fields, "decisions"))
|
|
850
900
|
});
|
|
851
901
|
}
|
|
852
902
|
function sessionSteps(record) {
|
|
853
903
|
return record.steps ?? [];
|
|
854
904
|
}
|
|
855
|
-
function
|
|
856
|
-
return record.
|
|
905
|
+
function sessionDecisions(record) {
|
|
906
|
+
return record.decisions ?? [];
|
|
857
907
|
}
|
|
858
908
|
function parseSessionRecord(text, file) {
|
|
859
909
|
let parsed;
|
|
@@ -1007,7 +1057,8 @@ function updateSession(root, sessionId, change) {
|
|
|
1007
1057
|
state: change.state ?? stored.state,
|
|
1008
1058
|
task: change.task === undefined ? stored.task : change.task,
|
|
1009
1059
|
phase: change.phase ?? stored.phase,
|
|
1010
|
-
steps: change.appendStep === undefined ? sessionSteps(stored) : [...sessionSteps(stored), change.appendStep]
|
|
1060
|
+
steps: change.appendStep === undefined ? sessionSteps(stored) : [...sessionSteps(stored), change.appendStep],
|
|
1061
|
+
decisions: change.decisions ?? sessionDecisions(stored)
|
|
1011
1062
|
});
|
|
1012
1063
|
writeRecordFile(file, record, false);
|
|
1013
1064
|
return record;
|
|
@@ -2142,8 +2193,32 @@ function openSqliteStore(repoRoot) {
|
|
|
2142
2193
|
}
|
|
2143
2194
|
|
|
2144
2195
|
// src/effort/sync/file.ts
|
|
2145
|
-
import { existsSync as
|
|
2146
|
-
import { join as
|
|
2196
|
+
import { existsSync as existsSync11 } from "fs";
|
|
2197
|
+
import { join as join13, resolve as resolve5 } from "path";
|
|
2198
|
+
|
|
2199
|
+
// src/cli/spends.ts
|
|
2200
|
+
var SPENDS_GLYPH = "\uD83E\uDE99";
|
|
2201
|
+
|
|
2202
|
+
// src/cli/command.ts
|
|
2203
|
+
var MAX_EXIT_CODE = 255;
|
|
2204
|
+
|
|
2205
|
+
class CommandExit extends Error {
|
|
2206
|
+
exitCode;
|
|
2207
|
+
constructor(exitCode, message = "") {
|
|
2208
|
+
super(message);
|
|
2209
|
+
if (!Number.isInteger(exitCode) || exitCode < 0 || exitCode > MAX_EXIT_CODE) {
|
|
2210
|
+
throw new TypeError(`CommandExit: exit code is ${describeValue(exitCode)}, expected a whole number from 0 to ${MAX_EXIT_CODE}`);
|
|
2211
|
+
}
|
|
2212
|
+
this.name = "CommandExit";
|
|
2213
|
+
this.exitCode = exitCode;
|
|
2214
|
+
}
|
|
2215
|
+
}
|
|
2216
|
+
function isTopLevel(command) {
|
|
2217
|
+
return command.subject === command.action;
|
|
2218
|
+
}
|
|
2219
|
+
function commandSpelling(command) {
|
|
2220
|
+
return isTopLevel(command) ? command.subject : `${command.subject} ${command.action}`;
|
|
2221
|
+
}
|
|
2147
2222
|
|
|
2148
2223
|
// src/effort/store/fix-schema.ts
|
|
2149
2224
|
import { existsSync as existsSync8 } from "fs";
|
|
@@ -2517,7 +2592,7 @@ function withoutWayOut(message, nextStep) {
|
|
|
2517
2592
|
|
|
2518
2593
|
// src/commands/plan/plan-files.ts
|
|
2519
2594
|
import { statSync as statSync3 } from "fs";
|
|
2520
|
-
import { resolve as resolve4 } from "path";
|
|
2595
|
+
import { basename as basename4, dirname as dirname11, join as join11, resolve as resolve4 } from "path";
|
|
2521
2596
|
|
|
2522
2597
|
// src/config-load.ts
|
|
2523
2598
|
import { existsSync as existsSync9, readFileSync as readFileSync8, realpathSync as realpathSync5 } from "fs";
|
|
@@ -2588,11 +2663,6 @@ function resolveProjectConfig(project, command, warn) {
|
|
|
2588
2663
|
`));
|
|
2589
2664
|
}
|
|
2590
2665
|
}
|
|
2591
|
-
var CHECKBOXES = {
|
|
2592
|
-
unchecked: "[ ]",
|
|
2593
|
-
blocked: "[BLOCKED]",
|
|
2594
|
-
done: "[x]"
|
|
2595
|
-
};
|
|
2596
2666
|
function countTasks(tasks) {
|
|
2597
2667
|
const done = tasks.filter((task) => task.status === "done").length;
|
|
2598
2668
|
const blocked = tasks.filter((task) => task.status === "blocked").length;
|
|
@@ -2601,9 +2671,6 @@ function countTasks(tasks) {
|
|
|
2601
2671
|
function formatCounts(counts) {
|
|
2602
2672
|
return `${counts.done}/${counts.total} done, ${counts.blocked} blocked, ${counts.open} open`;
|
|
2603
2673
|
}
|
|
2604
|
-
function checkbox(status) {
|
|
2605
|
-
return CHECKBOXES[status];
|
|
2606
|
-
}
|
|
2607
2674
|
function planFileName(stub, tracker) {
|
|
2608
2675
|
return tracker ? `PLAN_TRACKER-${stub}.md` : `PLAN-${stub}.md`;
|
|
2609
2676
|
}
|
|
@@ -2614,6 +2681,11 @@ function stubOfPlanFile(name2) {
|
|
|
2614
2681
|
function isFile(path) {
|
|
2615
2682
|
return statSync3(path, { throwIfNoEntry: false })?.isFile() ?? false;
|
|
2616
2683
|
}
|
|
2684
|
+
var REJECTED_DIR = "rejected";
|
|
2685
|
+
function rejectedPath(path) {
|
|
2686
|
+
const parent = dirname11(path);
|
|
2687
|
+
return parent === "." ? join11(REJECTED_DIR, basename4(path)) : join11(parent, REJECTED_DIR, basename4(path));
|
|
2688
|
+
}
|
|
2617
2689
|
function issueLine(file, issue) {
|
|
2618
2690
|
return `${file}:${issue.line}: ${issue.reason}: ${issue.text}`;
|
|
2619
2691
|
}
|
|
@@ -2634,15 +2706,6 @@ function expectOneArgument(args, usage) {
|
|
|
2634
2706
|
throw new CommandExit(1, `\u274C Expected one argument, got ${got}
|
|
2635
2707
|
Usage: ${usage}`);
|
|
2636
2708
|
}
|
|
2637
|
-
function expectAtMostOneArgument(args, usage) {
|
|
2638
|
-
const [only] = args;
|
|
2639
|
-
if (only === undefined)
|
|
2640
|
-
return null;
|
|
2641
|
-
if (args.length === 1)
|
|
2642
|
-
return only;
|
|
2643
|
-
throw new CommandExit(1, `\u274C Expected at most one argument, got ${args.length}: ${args.join(" ")}
|
|
2644
|
-
Usage: ${usage}`);
|
|
2645
|
-
}
|
|
2646
2709
|
function readSwitch(name2, value, hint) {
|
|
2647
2710
|
if (value === undefined || value === false || value === "false")
|
|
2648
2711
|
return false;
|
|
@@ -2789,10 +2852,10 @@ var fix_schema_default = createFixSchemaCommand();
|
|
|
2789
2852
|
|
|
2790
2853
|
// src/effort/store/merge-store.ts
|
|
2791
2854
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
2792
|
-
import { existsSync as
|
|
2855
|
+
import { existsSync as existsSync10, mkdtempSync, rmSync as rmSync7 } from "fs";
|
|
2793
2856
|
import { tmpdir as tmpdir3 } from "os";
|
|
2794
|
-
import { dirname as
|
|
2795
|
-
import { Database as
|
|
2857
|
+
import { dirname as dirname12, join as join12 } from "path";
|
|
2858
|
+
import { Database as Database5, SQLiteError as SQLiteError2 } from "bun:sqlite";
|
|
2796
2859
|
|
|
2797
2860
|
// src/effort/commits.ts
|
|
2798
2861
|
import { execFileSync } from "child_process";
|
|
@@ -3200,14 +3263,7 @@ function settleTable(local, other, union, trail) {
|
|
|
3200
3263
|
function settleMatches(local, other, unions, trail) {
|
|
3201
3264
|
return local.transaction(() => unions.map((union) => settleTable(local, other, union, trail)))();
|
|
3202
3265
|
}
|
|
3203
|
-
|
|
3204
3266
|
// src/effort/store/migrate.ts
|
|
3205
|
-
import { existsSync as existsSync10 } from "fs";
|
|
3206
|
-
import { Database as Database5 } from "bun:sqlite";
|
|
3207
|
-
var LIVE2 = "live";
|
|
3208
|
-
function asidePaths2(path, first, stamp) {
|
|
3209
|
-
return { parallelPath: `${path}.migrate-${stamp}`, backupPath: `${path}.before-${first}-${stamp}.bak` };
|
|
3210
|
-
}
|
|
3211
3267
|
function liveLoop(path, options, nothingDone = "Nothing was migrated.", ownSessionId = null) {
|
|
3212
3268
|
const root = storeProjectRoot(path);
|
|
3213
3269
|
if (root === null)
|
|
@@ -3220,71 +3276,6 @@ function liveLoop(path, options, nothingDone = "Nothing was migrated.", ownSessi
|
|
|
3220
3276
|
}
|
|
3221
3277
|
return records.find((record) => (record.state === "running" || record.state === "paused") && record.sessionId !== ownSessionId);
|
|
3222
3278
|
}
|
|
3223
|
-
function refuseLiveLoop2(path, breaking, options) {
|
|
3224
|
-
const loop = liveLoop(path, options);
|
|
3225
|
-
if (loop === undefined)
|
|
3226
|
-
return;
|
|
3227
|
-
const named = `loop ${loop.sessionId} (pid ${String(loop.pid)}, plan ${loop.planStub ?? loop.plan}) is running on this store`;
|
|
3228
|
-
const [first] = breaking;
|
|
3229
|
-
const opening = first === undefined ? `REFUSED \u2014 ${named}, and swapping the migrated store in under it would lose what it writes.` : `REFUSED \u2014 migration ${first} breaks older runtimes, and ${named}.`;
|
|
3230
|
-
throw new RebuildRefusal(`${opening} Nothing was migrated. Finish or stop that loop, then run it again.`);
|
|
3231
|
-
}
|
|
3232
|
-
function buildMigrated(path, parallelPath, migrations, stamp) {
|
|
3233
|
-
vacuumInto(path, parallelPath);
|
|
3234
|
-
const db = new Database5(parallelPath, { readwrite: true });
|
|
3235
|
-
try {
|
|
3236
|
-
const brought = bringForward(db, parallelPath, "write", "migrate", { migrations, ...stamp, builtAside: true });
|
|
3237
|
-
db.run(`ATTACH DATABASE ? AS ${LIVE2}`, [path]);
|
|
3238
|
-
const live = new Set(tableNames(db, LIVE2));
|
|
3239
|
-
const counted = checkedCounts(db, tableNames(db, "main").filter((table) => live.has(table)), LIVE2);
|
|
3240
|
-
db.run(`DETACH DATABASE ${LIVE2}`);
|
|
3241
|
-
refuseCorrupt(db);
|
|
3242
|
-
refuseUnusable(db, parallelPath, migrations);
|
|
3243
|
-
return { userVersion: brought.userVersion, counted };
|
|
3244
|
-
} finally {
|
|
3245
|
-
db.close();
|
|
3246
|
-
}
|
|
3247
|
-
}
|
|
3248
|
-
function migrateStore(options) {
|
|
3249
|
-
const { path, dryRun, stamp } = options;
|
|
3250
|
-
guardTestProcess(path);
|
|
3251
|
-
const migrations = options.migrations ?? SQLITE_MIGRATIONS;
|
|
3252
|
-
const appliedBy = appliedByName(options.identity ?? readRuntimeIdentity());
|
|
3253
|
-
const nothing = { applying: [], breaking: [], unknown: [], userVersion: null, counted: [], backupPath: null };
|
|
3254
|
-
if (!existsSync10(path)) {
|
|
3255
|
-
return { path, status: "missing", storeVersion: null, logged: false, appliedBy, ...nothing };
|
|
3256
|
-
}
|
|
3257
|
-
refuseInFlight(path);
|
|
3258
|
-
const store = readOnlySchema(path);
|
|
3259
|
-
const found = { path, storeVersion: store.userVersion, logged: store.log !== null, appliedBy };
|
|
3260
|
-
const plan = planSchema(store, sqliteCatalogue(migrations), "write", "migrate");
|
|
3261
|
-
if (plan.verdict === "refuse")
|
|
3262
|
-
throw new RebuildRefusal(plan.message);
|
|
3263
|
-
const applying = writeNames(plan);
|
|
3264
|
-
const planned = {
|
|
3265
|
-
applying,
|
|
3266
|
-
breaking: plan.pending.filter(({ breaks }) => breaks.length > 0).map(({ id }) => id),
|
|
3267
|
-
unknown: plan.unknown
|
|
3268
|
-
};
|
|
3269
|
-
if (applying.length === 0)
|
|
3270
|
-
return { ...found, ...nothing, ...planned, status: "current" };
|
|
3271
|
-
if (!dryRun) {
|
|
3272
|
-
refuseUnownedDevelopmentWrite(path, applying, options);
|
|
3273
|
-
refuseLiveLoop2(path, planned.breaking, options);
|
|
3274
|
-
}
|
|
3275
|
-
const first = plan.pending[0]?.id ?? ADOPTION_NAME;
|
|
3276
|
-
const { built, backupPath } = rebuildAside({
|
|
3277
|
-
path,
|
|
3278
|
-
...asidePaths2(path, first, stamp),
|
|
3279
|
-
dryRun,
|
|
3280
|
-
build: (parallelPath) => buildMigrated(path, parallelPath, migrations, {
|
|
3281
|
-
appliedBy,
|
|
3282
|
-
now: options.now ?? (() => new Date)
|
|
3283
|
-
})
|
|
3284
|
-
});
|
|
3285
|
-
const status = dryRun ? "would-migrate" : "migrated";
|
|
3286
|
-
return { ...found, ...planned, ...built, status, backupPath };
|
|
3287
|
-
}
|
|
3288
3279
|
|
|
3289
3280
|
// src/effort/store/merge-store.ts
|
|
3290
3281
|
var MOVE_TO_SQLITE = "rafa effort move --to=sqlite";
|
|
@@ -3297,7 +3288,7 @@ class MergeRefusal extends RebuildRefusal {
|
|
|
3297
3288
|
this.reason = reason;
|
|
3298
3289
|
}
|
|
3299
3290
|
}
|
|
3300
|
-
var
|
|
3291
|
+
var LIVE2 = "live";
|
|
3301
3292
|
var MERGES_TABLE = "merges";
|
|
3302
3293
|
var INSERT_MERGE = `INSERT INTO merges (id, other_store, merged_at, rows_added, rows_skipped, rows_in_conflict)
|
|
3303
3294
|
VALUES (?, ?, ?, ?, ?, ?)`;
|
|
@@ -3308,14 +3299,14 @@ function refuseNdjson(backend) {
|
|
|
3308
3299
|
throw new MergeRefusal("ndjson", `REFUSED \u2014 this project keeps its sessions and commits as NDJSON (store: ndjson), and a merge needs the SQLite store. ${NOTHING_MERGED}` + ` Next safe step: ${MOVE_TO_SQLITE}`);
|
|
3309
3300
|
}
|
|
3310
3301
|
function refuseMissing(path, which) {
|
|
3311
|
-
if (
|
|
3302
|
+
if (existsSync10(path))
|
|
3312
3303
|
return;
|
|
3313
3304
|
throw new MergeRefusal("missing", `REFUSED \u2014 ${which} ${path} is not there. ${NOTHING_MERGED}`);
|
|
3314
3305
|
}
|
|
3315
3306
|
function refuseDamaged(path) {
|
|
3316
3307
|
let answers;
|
|
3317
3308
|
try {
|
|
3318
|
-
const db = new
|
|
3309
|
+
const db = new Database5(path, { readonly: true });
|
|
3319
3310
|
try {
|
|
3320
3311
|
answers = db.query("PRAGMA integrity_check").all().map((row) => row.integrity_check);
|
|
3321
3312
|
} finally {
|
|
@@ -3337,7 +3328,7 @@ function writablePlan(path, migrations) {
|
|
|
3337
3328
|
return plan;
|
|
3338
3329
|
}
|
|
3339
3330
|
function recordedMeta(path) {
|
|
3340
|
-
const db = new
|
|
3331
|
+
const db = new Database5(path, { readonly: true });
|
|
3341
3332
|
try {
|
|
3342
3333
|
const hasTable = db.query("SELECT count(*) AS n FROM sqlite_master WHERE type = 'table' AND name = 'store_meta'").get()?.n === 1;
|
|
3343
3334
|
return hasTable ? readStoreMeta(db) : null;
|
|
@@ -3347,14 +3338,14 @@ function recordedMeta(path) {
|
|
|
3347
3338
|
}
|
|
3348
3339
|
function refuseOtherProject(options) {
|
|
3349
3340
|
const other = recordedMeta(options.otherPath);
|
|
3350
|
-
const here = recordedMeta(options.path)?.projectRootCommit ?? (options.readProject ?? readProjectIdentity)(
|
|
3341
|
+
const here = recordedMeta(options.path)?.projectRootCommit ?? (options.readProject ?? readProjectIdentity)(dirname12(options.path)).rootCommit;
|
|
3351
3342
|
const there = other?.projectRootCommit ?? null;
|
|
3352
3343
|
if (here !== null && there !== null && here !== there) {
|
|
3353
3344
|
throw new MergeRefusal("other-project", `REFUSED \u2014 ${options.otherPath} is the effort store of another project (root commit ${there});` + ` this store's project has root commit ${here}. ${NOTHING_MERGED}`);
|
|
3354
3345
|
}
|
|
3355
3346
|
return other?.storeId ?? null;
|
|
3356
3347
|
}
|
|
3357
|
-
function
|
|
3348
|
+
function refuseLiveLoop2(path, options, sessionId) {
|
|
3358
3349
|
const loop = liveLoop(path, options, NOTHING_MERGED, sessionId);
|
|
3359
3350
|
if (loop === undefined)
|
|
3360
3351
|
return;
|
|
@@ -3363,18 +3354,18 @@ function refuseLiveLoop3(path, options, sessionId) {
|
|
|
3363
3354
|
function openOther(otherPath, plan, stamp) {
|
|
3364
3355
|
const needs = writeNames(plan);
|
|
3365
3356
|
if (needs.length === 0) {
|
|
3366
|
-
const db = new
|
|
3357
|
+
const db = new Database5(otherPath, { readonly: true });
|
|
3367
3358
|
return { db, broughtForward: [], release: () => db.close() };
|
|
3368
3359
|
}
|
|
3369
|
-
const dir = mkdtempSync(
|
|
3360
|
+
const dir = mkdtempSync(join12(tmpdir3(), "rafa-merge-other-"));
|
|
3370
3361
|
const release = (db) => {
|
|
3371
3362
|
db?.close();
|
|
3372
3363
|
rmSync7(dir, { recursive: true, force: true });
|
|
3373
3364
|
};
|
|
3374
3365
|
try {
|
|
3375
|
-
const copyPath =
|
|
3366
|
+
const copyPath = join12(dir, "other.sqlite");
|
|
3376
3367
|
vacuumInto(otherPath, copyPath);
|
|
3377
|
-
const db = new
|
|
3368
|
+
const db = new Database5(copyPath, { readwrite: true });
|
|
3378
3369
|
try {
|
|
3379
3370
|
bringForward(db, copyPath, "write", "open", { ...stamp, builtAside: true });
|
|
3380
3371
|
} catch (error) {
|
|
@@ -3418,14 +3409,14 @@ function addedRows(merged) {
|
|
|
3418
3409
|
}
|
|
3419
3410
|
function buildMerged(path, parallelPath, other, merge2) {
|
|
3420
3411
|
vacuumInto(path, parallelPath);
|
|
3421
|
-
const db = new
|
|
3412
|
+
const db = new Database5(parallelPath, { readwrite: true });
|
|
3422
3413
|
try {
|
|
3423
3414
|
bringForward(db, parallelPath, "write", "open", { ...merge2.stamp, builtAside: true });
|
|
3424
3415
|
const merged = mergeInto(db, other, merge2.id, merge2.otherStore, merge2.stamp.now().toISOString());
|
|
3425
|
-
db.run(`ATTACH DATABASE ? AS ${
|
|
3426
|
-
const live = new Set(tableNames(db,
|
|
3427
|
-
checkedCounts(db, tableNames(db, "main").filter((table) => live.has(table)),
|
|
3428
|
-
db.run(`DETACH DATABASE ${
|
|
3416
|
+
db.run(`ATTACH DATABASE ? AS ${LIVE2}`, [path]);
|
|
3417
|
+
const live = new Set(tableNames(db, LIVE2));
|
|
3418
|
+
checkedCounts(db, tableNames(db, "main").filter((table) => live.has(table)), LIVE2, addedRows(merged));
|
|
3419
|
+
db.run(`DETACH DATABASE ${LIVE2}`);
|
|
3429
3420
|
refuseCorrupt(db);
|
|
3430
3421
|
refuseUnusable(db, parallelPath, merge2.stamp.migrations);
|
|
3431
3422
|
return merged;
|
|
@@ -3446,7 +3437,7 @@ function refuseUnmergeable(options, migrations) {
|
|
|
3446
3437
|
const otherStore = refuseOtherProject(options);
|
|
3447
3438
|
if (!options.dryRun) {
|
|
3448
3439
|
refuseUnownedDevelopmentWrite(path, [...writeNames(localPlan), MERGES_TABLE], options);
|
|
3449
|
-
|
|
3440
|
+
refuseLiveLoop2(path, options, options.sessionId ?? null);
|
|
3450
3441
|
}
|
|
3451
3442
|
return { otherPlan, otherStore };
|
|
3452
3443
|
}
|
|
@@ -3494,7 +3485,7 @@ function refuseUncarriable(backend, source) {
|
|
|
3494
3485
|
if (backend === "ndjson") {
|
|
3495
3486
|
throw new FileSyncRefusal(`${REFUSAL}: this project keeps its sessions and commits as NDJSON (store: ndjson), and the file carried` + ` is effort.sqlite, which would hold none of them. ${NOTHING_COPIED} Next safe step: ${MOVE_TO_SQLITE}`);
|
|
3496
3487
|
}
|
|
3497
|
-
if (!
|
|
3488
|
+
if (!existsSync11(join13(source, SQLITE_STORE_FILE_NAME))) {
|
|
3498
3489
|
throw new FileSyncRefusal(`${REFUSAL}: no ${SQLITE_STORE_FILE_NAME} in ${source}. ${NOTHING_COPIED}`);
|
|
3499
3490
|
}
|
|
3500
3491
|
}
|
|
@@ -3512,11 +3503,11 @@ function createFileSync(options) {
|
|
|
3512
3503
|
const source = storeDir();
|
|
3513
3504
|
refuseUncarriable(backend, source);
|
|
3514
3505
|
const copied = copyEffortStore({ source, target });
|
|
3515
|
-
return Object.freeze({ status: "pushed", path:
|
|
3506
|
+
return Object.freeze({ status: "pushed", path: join13(copied.directory, SQLITE_STORE_FILE_NAME) });
|
|
3516
3507
|
};
|
|
3517
3508
|
const pull = async ({ from, dryRun, sessionId = null }) => {
|
|
3518
3509
|
const otherPath = resolve5(repoRoot, requirePath("from", from));
|
|
3519
|
-
const path =
|
|
3510
|
+
const path = join13(storeDir(), SQLITE_STORE_FILE_NAME);
|
|
3520
3511
|
const stamp = fileStamp(now());
|
|
3521
3512
|
const merge2 = mergeStore({ ...mergeSeams(options), path, otherPath, backend, dryRun, stamp, now, sessionId });
|
|
3522
3513
|
return Object.freeze({ status: "pulled", merge: merge2 });
|
|
@@ -3585,15 +3576,15 @@ function selectSync(repoRoot, config, registry = CORE_ADAPTER_REGISTRY) {
|
|
|
3585
3576
|
|
|
3586
3577
|
// src/adapters/learning/local.ts
|
|
3587
3578
|
import { appendFile, mkdir, readFile, rm, writeFile } from "fs/promises";
|
|
3588
|
-
import { join as
|
|
3579
|
+
import { join as join16 } from "path";
|
|
3589
3580
|
|
|
3590
3581
|
// src/commands/instinct/instinct-records.ts
|
|
3591
3582
|
import { readdirSync as readdirSync4, readFileSync as readFileSync9, statSync as statSync5 } from "fs";
|
|
3592
|
-
import { join as
|
|
3583
|
+
import { join as join15 } from "path";
|
|
3593
3584
|
|
|
3594
3585
|
// src/check/layout.ts
|
|
3595
3586
|
import { readdirSync as readdirSync3, statSync as statSync4 } from "fs";
|
|
3596
|
-
import { join as
|
|
3587
|
+
import { join as join14, relative as relative2 } from "path";
|
|
3597
3588
|
var SKILL_FILE = "SKILL.md";
|
|
3598
3589
|
var MARKDOWN_EXTENSION = ".md";
|
|
3599
3590
|
var LAYOUT_SEVERITY = Object.freeze({
|
|
@@ -3710,7 +3701,7 @@ function scanGroupMember(root, dir, name2) {
|
|
|
3710
3701
|
const children = visibleNames(dir);
|
|
3711
3702
|
if (children.length === 0)
|
|
3712
3703
|
return [dotfileOnlyEntry("skill", root, dir)];
|
|
3713
|
-
const skillPath =
|
|
3704
|
+
const skillPath = join14(dir, SKILL_FILE);
|
|
3714
3705
|
if (children.includes(SKILL_FILE) && entryKind(skillPath) === "file") {
|
|
3715
3706
|
return [nestedGroupEntry(root, skillPath, name2)];
|
|
3716
3707
|
}
|
|
@@ -3719,7 +3710,7 @@ function scanGroupMember(root, dir, name2) {
|
|
|
3719
3710
|
function scanSkillGroup(root, dir, children) {
|
|
3720
3711
|
const entries = [];
|
|
3721
3712
|
for (const child of children) {
|
|
3722
|
-
const path =
|
|
3713
|
+
const path = join14(dir, child);
|
|
3723
3714
|
const found = entryKind(path);
|
|
3724
3715
|
if (found === null) {
|
|
3725
3716
|
entries.push(unreadableEntry("skill", root, path));
|
|
@@ -3740,7 +3731,7 @@ function scanSkillDirectory(root, dir, name2) {
|
|
|
3740
3731
|
const children = visibleNames(dir);
|
|
3741
3732
|
if (children.length === 0)
|
|
3742
3733
|
return [dotfileOnlyEntry("skill", root, dir)];
|
|
3743
|
-
const skillPath =
|
|
3734
|
+
const skillPath = join14(dir, SKILL_FILE);
|
|
3744
3735
|
if (children.includes(SKILL_FILE) && entryKind(skillPath) === "file") {
|
|
3745
3736
|
return [skillFileEntry(skillPath, name2)];
|
|
3746
3737
|
}
|
|
@@ -3749,7 +3740,7 @@ function scanSkillDirectory(root, dir, name2) {
|
|
|
3749
3740
|
function scanSkillRoot(root) {
|
|
3750
3741
|
const entries = [];
|
|
3751
3742
|
for (const name2 of visibleNames(root)) {
|
|
3752
|
-
const path =
|
|
3743
|
+
const path = join14(root, name2);
|
|
3753
3744
|
const found = entryKind(path);
|
|
3754
3745
|
if (found === null) {
|
|
3755
3746
|
entries.push(unreadableEntry("skill", root, path));
|
|
@@ -3770,7 +3761,7 @@ function scanInstinctSubdirectory(root, dir) {
|
|
|
3770
3761
|
return [dotfileOnlyEntry("instinct", root, dir)];
|
|
3771
3762
|
const entries = [];
|
|
3772
3763
|
for (const child of children) {
|
|
3773
|
-
const path =
|
|
3764
|
+
const path = join14(dir, child);
|
|
3774
3765
|
const found = entryKind(path);
|
|
3775
3766
|
if (found === null) {
|
|
3776
3767
|
entries.push(unreadableEntry("instinct", root, path));
|
|
@@ -3788,7 +3779,7 @@ function scanInstinctSubdirectory(root, dir) {
|
|
|
3788
3779
|
function scanInstinctRoot(root) {
|
|
3789
3780
|
const entries = [];
|
|
3790
3781
|
for (const name2 of visibleNames(root)) {
|
|
3791
|
-
const path =
|
|
3782
|
+
const path = join14(root, name2);
|
|
3792
3783
|
const found = entryKind(path);
|
|
3793
3784
|
if (found === null) {
|
|
3794
3785
|
entries.push(unreadableEntry("instinct", root, path));
|
|
@@ -4257,7 +4248,7 @@ function isFile2(path) {
|
|
|
4257
4248
|
}
|
|
4258
4249
|
}
|
|
4259
4250
|
function recordFiles(dir) {
|
|
4260
|
-
return readdirSync4(dir).filter((name2) => isRecordFile(name2) && isFile2(
|
|
4251
|
+
return readdirSync4(dir).filter((name2) => isRecordFile(name2) && isFile2(join15(dir, name2))).sort((left, right) => left.localeCompare(right));
|
|
4261
4252
|
}
|
|
4262
4253
|
function readScope(scope, dir) {
|
|
4263
4254
|
if (!tierExists(dir))
|
|
@@ -4266,23 +4257,12 @@ function readScope(scope, dir) {
|
|
|
4266
4257
|
scope,
|
|
4267
4258
|
dir,
|
|
4268
4259
|
exists: true,
|
|
4269
|
-
records: recordFiles(dir).map((name2) => readRecord(
|
|
4260
|
+
records: recordFiles(dir).map((name2) => readRecord(join15(dir, name2), scope, recordId(name2)))
|
|
4270
4261
|
};
|
|
4271
4262
|
}
|
|
4272
4263
|
function readScopes(seams) {
|
|
4273
4264
|
return resolveInstinctScopes(seams).map((location) => readScope(location.scope, location.dir));
|
|
4274
4265
|
}
|
|
4275
|
-
function allRecords(listings) {
|
|
4276
|
-
return listings.flatMap((listing) => listing.records);
|
|
4277
|
-
}
|
|
4278
|
-
function findRecords(listings, id) {
|
|
4279
|
-
return allRecords(listings).filter((entry) => entry.id === id);
|
|
4280
|
-
}
|
|
4281
|
-
function instinctProject(context, name2) {
|
|
4282
|
-
if (context.project === null)
|
|
4283
|
-
throw new Error(`${name2} runs inside a project, and was handed none`);
|
|
4284
|
-
return context.project;
|
|
4285
|
-
}
|
|
4286
4266
|
|
|
4287
4267
|
// src/adapters/learning/held.ts
|
|
4288
4268
|
function compareText2(left, right) {
|
|
@@ -4569,7 +4549,7 @@ function heldChanges(dir, held, result, described) {
|
|
|
4569
4549
|
if (issue2 !== undefined) {
|
|
4570
4550
|
throw new Error(`${PUSH_REFUSAL}: ${file} would not read back: ${issue2.field}: ${issue2.message}`);
|
|
4571
4551
|
}
|
|
4572
|
-
const path =
|
|
4552
|
+
const path = join16(dir, file);
|
|
4573
4553
|
if (held.unreadable.has(path)) {
|
|
4574
4554
|
throw new Error(`${PUSH_REFUSAL}: it would overwrite ${path}, which could not be read`);
|
|
4575
4555
|
}
|
|
@@ -4599,18 +4579,18 @@ function pushLogLines(sourceId, described, result) {
|
|
|
4599
4579
|
});
|
|
4600
4580
|
}
|
|
4601
4581
|
function localInstinctsDir(repoRoot) {
|
|
4602
|
-
return
|
|
4582
|
+
return join16(repoRoot, RAFA_INSTINCTS_PATH);
|
|
4603
4583
|
}
|
|
4604
4584
|
function userInstinctsDir(home) {
|
|
4605
|
-
return
|
|
4585
|
+
return join16(home, RAFA_INSTINCTS_PATH);
|
|
4606
4586
|
}
|
|
4607
4587
|
function createLocalLearning(options) {
|
|
4608
4588
|
const { instinctsDir, minConfidence } = options;
|
|
4609
4589
|
const userDir = userInstinctsDir(options.home);
|
|
4610
4590
|
const now = options.now ?? (() => new Date().toISOString());
|
|
4611
4591
|
const warn = options.warn ?? warnThroughActiveOutput;
|
|
4612
|
-
const instinctsPath =
|
|
4613
|
-
const flagsPath =
|
|
4592
|
+
const instinctsPath = join16(instinctsDir, INSTINCTS_FILE);
|
|
4593
|
+
const flagsPath = join16(instinctsDir, FLAGS_FILE);
|
|
4614
4594
|
function readHeld(scope, dir) {
|
|
4615
4595
|
const { records } = readScope(scope, dir);
|
|
4616
4596
|
const unreadable = new Set;
|
|
@@ -4755,7 +4735,7 @@ function createJsonOutput({
|
|
|
4755
4735
|
}
|
|
4756
4736
|
|
|
4757
4737
|
// src/adapters/planner/claude.ts
|
|
4758
|
-
import { existsSync as
|
|
4738
|
+
import { existsSync as existsSync12 } from "fs";
|
|
4759
4739
|
import { mkdir as mkdir2, readFile as readFile2 } from "fs/promises";
|
|
4760
4740
|
import { posix, resolve as resolve6 } from "path";
|
|
4761
4741
|
|
|
@@ -5097,7 +5077,7 @@ function createClaudePlanner(options) {
|
|
|
5097
5077
|
const create = async ({ specPath, stub }) => {
|
|
5098
5078
|
const planPath = planFilePath(planDir, `PLAN-${stub}.md`);
|
|
5099
5079
|
const prerequisitesPath = planFilePath(planDir, `PREREQUISITES-${stub}.md`);
|
|
5100
|
-
const isWritten = (path) =>
|
|
5080
|
+
const isWritten = (path) => existsSync12(resolve6(root, path));
|
|
5101
5081
|
if (isWritten(planPath)) {
|
|
5102
5082
|
throw new ClaudePlannerError(`${planPath} already exists`, FAILURE_EXIT_CODE);
|
|
5103
5083
|
}
|
|
@@ -5618,7 +5598,7 @@ function createGithubTracker(options) {
|
|
|
5618
5598
|
|
|
5619
5599
|
// src/adapters/tracker/local.ts
|
|
5620
5600
|
import { mkdir as mkdir3, readdir, readFile as readFile3, writeFile as writeFile2 } from "fs/promises";
|
|
5621
|
-
import { join as
|
|
5601
|
+
import { join as join17 } from "path";
|
|
5622
5602
|
var PREFIX4 = "local tracker";
|
|
5623
5603
|
var FRONTMATTER = /^---\n([\s\S]*?)\n---\n([\s\S]*)$/;
|
|
5624
5604
|
var ISSUE_NUMBER2 = /^[1-9]\d*$/;
|
|
@@ -5683,7 +5663,7 @@ function issueNumberOfFile(name2) {
|
|
|
5683
5663
|
return name2.endsWith(ISSUE_EXTENSION) ? parseIssueNumber(name2.slice(0, -ISSUE_EXTENSION.length)) : null;
|
|
5684
5664
|
}
|
|
5685
5665
|
function issuePath(issuesDir, number) {
|
|
5686
|
-
return
|
|
5666
|
+
return join17(issuesDir, `${number}${ISSUE_EXTENSION}`);
|
|
5687
5667
|
}
|
|
5688
5668
|
async function issueNumbers(issuesDir) {
|
|
5689
5669
|
let names;
|
|
@@ -5697,7 +5677,7 @@ async function issueNumbers(issuesDir) {
|
|
|
5697
5677
|
return names.map(issueNumberOfFile).filter((number) => number !== null).sort((a, b) => a - b);
|
|
5698
5678
|
}
|
|
5699
5679
|
function localIssuesDir(repoRoot) {
|
|
5700
|
-
return
|
|
5680
|
+
return join17(repoRoot, ".rafa", "issues");
|
|
5701
5681
|
}
|
|
5702
5682
|
function renderLocalIssue(record) {
|
|
5703
5683
|
const { draft } = record;
|
|
@@ -6191,65 +6171,11 @@ function requireTrustedAuthor(item, reading) {
|
|
|
6191
6171
|
return;
|
|
6192
6172
|
throw new CommandExit(TRUST_REFUSAL_EXIT, trustRefusalMessage(item, reading));
|
|
6193
6173
|
}
|
|
6194
|
-
var USER_COMMAND = "gh api user";
|
|
6195
|
-
function noLogin(detail) {
|
|
6196
|
-
return { login: null, detail };
|
|
6197
|
-
}
|
|
6198
|
-
function createGhEditorLogin(options) {
|
|
6199
|
-
const { gh } = options;
|
|
6200
|
-
return async () => {
|
|
6201
|
-
const result = await gh(["api", "user"]);
|
|
6202
|
-
if (!result.ok)
|
|
6203
|
-
return noLogin(detailOf2(result, USER_COMMAND));
|
|
6204
|
-
let payload;
|
|
6205
|
-
try {
|
|
6206
|
-
payload = JSON.parse(result.stdout);
|
|
6207
|
-
} catch (error) {
|
|
6208
|
-
return noLogin(`${USER_COMMAND} wrote output that is not JSON: ${messageOf(error)}`);
|
|
6209
|
-
}
|
|
6210
|
-
if (!isMapping(payload)) {
|
|
6211
|
-
return noLogin(`${USER_COMMAND} answered ${describeValue(payload)}, expected a mapping`);
|
|
6212
|
-
}
|
|
6213
|
-
const login = payload["login"];
|
|
6214
|
-
return typeof login === "string" && isGitHubLogin(login) ? { login, detail: "" } : noLogin(`${USER_COMMAND} answered ${describeValue(login)} as its login, which is not a GitHub login`);
|
|
6215
|
-
};
|
|
6216
|
-
}
|
|
6217
|
-
async function readEditorTrust(trust, editor) {
|
|
6218
|
-
const read = await editor();
|
|
6219
|
-
if (read.login === null) {
|
|
6220
|
-
return { login: null, trusted: false, refusal: "ownership-unknown", reading: null, detail: read.detail };
|
|
6221
|
-
}
|
|
6222
|
-
const reading = await readBoardTrust(trust, read.login);
|
|
6223
|
-
return {
|
|
6224
|
-
login: read.login,
|
|
6225
|
-
trusted: reading.trusted,
|
|
6226
|
-
refusal: editorRefusalOf(reading),
|
|
6227
|
-
reading,
|
|
6228
|
-
detail: ""
|
|
6229
|
-
};
|
|
6230
|
-
}
|
|
6231
|
-
function editorRefusalOf(reading) {
|
|
6232
|
-
if (reading.trusted)
|
|
6233
|
-
return null;
|
|
6234
|
-
return reading.refusal === "lookup-failed" ? "ownership-unknown" : "ownership";
|
|
6235
|
-
}
|
|
6236
|
-
function editorRefusalMessage(item, reading) {
|
|
6237
|
-
const what = `${item.kind} #${String(item.number)}`;
|
|
6238
|
-
if (reading.reading !== null) {
|
|
6239
|
-
const because = trustRefusalClause(item.repo, reading.reading);
|
|
6240
|
-
return `${what} cannot be edited by ${reading.reading.login}, ${because}; a member must make the edit`;
|
|
6241
|
-
}
|
|
6242
|
-
if (reading.trusted) {
|
|
6243
|
-
throw new TypeError("board trust: a trusted editor has no refusal to name");
|
|
6244
|
-
}
|
|
6245
|
-
const detail = reading.detail === "" ? UNREPORTED : reading.detail;
|
|
6246
|
-
return `${what} cannot be edited: the account running the edit could not be read (${detail}); ` + "log gh in with `gh auth login` and run it again";
|
|
6247
|
-
}
|
|
6248
6174
|
// src/effort/sync/wire.ts
|
|
6249
|
-
import { existsSync as
|
|
6175
|
+
import { existsSync as existsSync13, mkdtempSync as mkdtempSync2, rmSync as rmSync8 } from "fs";
|
|
6250
6176
|
import { tmpdir as tmpdir4 } from "os";
|
|
6251
|
-
import { join as
|
|
6252
|
-
import { Database as
|
|
6177
|
+
import { join as join18 } from "path";
|
|
6178
|
+
import { Database as Database6, SQLiteError as SQLiteError3 } from "bun:sqlite";
|
|
6253
6179
|
var WIRE_FORMAT = "rafa-effort-wire";
|
|
6254
6180
|
var WIRE_VERSION = 1;
|
|
6255
6181
|
|
|
@@ -6409,9 +6335,9 @@ function exportWirePayload(options) {
|
|
|
6409
6335
|
const { path } = options;
|
|
6410
6336
|
const cursor = checkCursor(options.cursor ?? {});
|
|
6411
6337
|
guardTestProcess(path);
|
|
6412
|
-
if (!
|
|
6338
|
+
if (!existsSync13(path))
|
|
6413
6339
|
throw new WireExportRefusal(`wire: ${path} is not there`);
|
|
6414
|
-
const db = new
|
|
6340
|
+
const db = new Database6(path, { readonly: true, safeIntegers: true });
|
|
6415
6341
|
try {
|
|
6416
6342
|
db.run(`PRAGMA busy_timeout = ${String(activeStoreSettings().busyTimeoutMs)}`);
|
|
6417
6343
|
return db.transaction(() => readPayload(db, path, cursor))();
|
|
@@ -6450,7 +6376,7 @@ function insertRows(db, table, rows) {
|
|
|
6450
6376
|
}
|
|
6451
6377
|
function buildStore(path, payload, options) {
|
|
6452
6378
|
const migrations = namedMigrations(payload.migrations, options.migrations ?? SQLITE_MIGRATIONS);
|
|
6453
|
-
const db = new
|
|
6379
|
+
const db = new Database6(path, { create: true, readwrite: true });
|
|
6454
6380
|
try {
|
|
6455
6381
|
bringForward(db, path, "write", "open", {
|
|
6456
6382
|
migrations,
|
|
@@ -6468,9 +6394,9 @@ function buildStore(path, payload, options) {
|
|
|
6468
6394
|
}
|
|
6469
6395
|
function materialiseWirePayload(payload, options = {}) {
|
|
6470
6396
|
const checked = checkPayload(payload);
|
|
6471
|
-
const directory = mkdtempSync2(
|
|
6397
|
+
const directory = mkdtempSync2(join18(options.tempDir ?? tmpdir4(), "rafa-wire-"));
|
|
6472
6398
|
const release = () => rmSync8(directory, { recursive: true, force: true });
|
|
6473
|
-
const path =
|
|
6399
|
+
const path = join18(directory, SQLITE_STORE_FILE_NAME);
|
|
6474
6400
|
try {
|
|
6475
6401
|
guardTestProcess(path);
|
|
6476
6402
|
buildStore(path, checked, options);
|
|
@@ -6498,4 +6424,4 @@ function selectEffortStore(repoRoot, config) {
|
|
|
6498
6424
|
return adapter.create({ repoRoot });
|
|
6499
6425
|
}
|
|
6500
6426
|
|
|
6501
|
-
export {
|
|
6427
|
+
export { EFFORT_DIR_VARIABLE, effortStoreDir, guardTestProcess, EFFORT_KEY_PROJECTIONS, openNdjsonStore, name, version, RAFA_VERSION, createGitRunner, gitSaid, NOT_A_REPOSITORY, mainCheckoutOf, SCOPE_DIR, INIT_COMMAND, DISK_FILE_SYSTEM, ScopeError, scopeAt, initHint, selfAndAncestors, resolveScope, positionFilePath, readPositionFile, writePositionFile, positionAt, goHome, hopFilePath, readHopRecord, writeHopRecord, staleAgainst, SessionRecordError, isSessionId, sessionDecisions, SessionConflictError, runsDir, sessionFilePath, errorCode, isPidAlive, readSessions, readSession, samePlan, beginSession, updateSession, DEVELOPMENT_NEXT_STEP, DevelopmentBuildRefusedError, refuseUnownedDevelopmentWrite, SQLITE_MIGRATIONS, sqliteCatalogue, planSchema, readStoreSchema, writeNames, ACROSS_STORES_ORDER, STAMPED_COLUMNS, stampedValues, activeStoreSettings, normalizeRemote, gitRemoteUrl, readStoreMeta, SQLITE_STORE_FILE_NAME, sqliteStorePath, LONE_SURROGATE, withSqliteStore, writeSqliteStore, openSqliteStore, SPENDS_GLYPH, CommandExit, commandSpelling, readConfigFile, loadConfig, plansDirAt, requireProject, resolvePlansDir, countTasks, formatCounts, planFileName, stubOfPlanFile, isFile, rejectedPath, issueLine, plural, expectNoArgument, expectOneArgument, readSwitch, minutesBetween, readCommitLog, MOVE_TO_SQLITE, mergeStore, SyncModuleMissing, selectSync, SKILL_FILE, MARKDOWN_EXTENSION, scanLayout, declaredNameIssue, readFrontmatterDocument, readFrontmatter, mergeFrontmatter, writeFrontmatter, parseInstinct, readScopes, padKind, oneLine, interruptClaudeSessions, spawnClaude, runClaude, runClaudeCaptured, planFilePath, ClaudePlannerError, GITHUB_LABELS, createGhRunner, typeOfLabels, moduleOfLabels, createLocalTracker, PORT_VERSIONS, createAdapterRegistry, CORE_ADAPTER_REGISTRY, TRUSTED_PERMISSIONS, ghBoardTrust, readBoardTrust, requireTrustedBoardAuthor, trustRefusalClause, WIRE_FORMAT, WIRE_VERSION, WireFormatError, WireExportRefusal, encodeWirePayload, decodeWirePayload, exportWirePayload, materialiseWirePayload, selectEffortStore };
|