agent-trajectories 0.5.2 → 0.5.4
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/{chunk-4MACDCF4.js → chunk-W222QB6V.js} +346 -41
- package/dist/chunk-W222QB6V.js.map +1 -0
- package/dist/cli/index.js +1739 -195
- package/dist/cli/index.js.map +1 -1
- package/dist/{index-Ce7r5yv0.d.ts → index-7tzw_CMS.d.ts} +122 -37
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/sdk/index.d.ts +1 -1
- package/dist/sdk/index.js +3 -1
- package/package.json +1 -1
- package/dist/chunk-4MACDCF4.js.map +0 -1
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
// src/sdk/client.ts
|
|
2
|
+
import { spawn } from "child_process";
|
|
3
|
+
import { existsSync as existsSync2, readFileSync } from "fs";
|
|
4
|
+
import { createRequire } from "module";
|
|
5
|
+
import { dirname, resolve as resolvePath } from "path";
|
|
6
|
+
|
|
1
7
|
// src/core/id.ts
|
|
2
8
|
import { webcrypto } from "crypto";
|
|
3
9
|
var ALPHABET = "abcdefghijklmnopqrstuvwxyz0123456789";
|
|
@@ -18,7 +24,7 @@ function generateChapterId() {
|
|
|
18
24
|
return `chap_${generateRandomId()}`;
|
|
19
25
|
}
|
|
20
26
|
function isValidTrajectoryId(id) {
|
|
21
|
-
return /^traj_[a-z0-
|
|
27
|
+
return /^traj_[a-z0-9_]+$/.test(id);
|
|
22
28
|
}
|
|
23
29
|
function isValidChapterId(id) {
|
|
24
30
|
return /^chap_[a-z0-9]{12}$/.test(id);
|
|
@@ -50,18 +56,20 @@ var TrajectoryStatusSchema = z.enum([
|
|
|
50
56
|
"completed",
|
|
51
57
|
"abandoned"
|
|
52
58
|
]);
|
|
53
|
-
var TrajectoryEventTypeSchema = z.
|
|
54
|
-
"prompt",
|
|
55
|
-
"thinking",
|
|
56
|
-
"tool_call",
|
|
57
|
-
"tool_result",
|
|
58
|
-
"message_sent",
|
|
59
|
-
"message_received",
|
|
60
|
-
"decision",
|
|
61
|
-
"finding",
|
|
62
|
-
"reflection",
|
|
63
|
-
"note",
|
|
64
|
-
"error"
|
|
59
|
+
var TrajectoryEventTypeSchema = z.union([
|
|
60
|
+
z.literal("prompt"),
|
|
61
|
+
z.literal("thinking"),
|
|
62
|
+
z.literal("tool_call"),
|
|
63
|
+
z.literal("tool_result"),
|
|
64
|
+
z.literal("message_sent"),
|
|
65
|
+
z.literal("message_received"),
|
|
66
|
+
z.literal("decision"),
|
|
67
|
+
z.literal("finding"),
|
|
68
|
+
z.literal("reflection"),
|
|
69
|
+
z.literal("note"),
|
|
70
|
+
z.literal("error"),
|
|
71
|
+
z.string()
|
|
72
|
+
// Allow event types emitted by other tools (e.g. agent-relay's completion-evidence / completion-marker). Downstream code filters to known types.
|
|
65
73
|
]);
|
|
66
74
|
var EventSignificanceSchema = z.enum([
|
|
67
75
|
"low",
|
|
@@ -91,7 +99,7 @@ var DecisionSchema = z.object({
|
|
|
91
99
|
});
|
|
92
100
|
var AgentParticipationSchema = z.object({
|
|
93
101
|
name: z.string().min(1, "Agent name is required"),
|
|
94
|
-
role: z.
|
|
102
|
+
role: z.string().min(1, "Agent role is required"),
|
|
95
103
|
joinedAt: z.string().datetime(),
|
|
96
104
|
leftAt: z.string().datetime().optional()
|
|
97
105
|
});
|
|
@@ -151,7 +159,7 @@ var TrajectoryTraceRefSchema = z.object({
|
|
|
151
159
|
traceId: z.string().optional()
|
|
152
160
|
});
|
|
153
161
|
var TrajectorySchema = z.object({
|
|
154
|
-
id: z.string().regex(/^traj_[a-z0-
|
|
162
|
+
id: z.string().regex(/^traj_[a-z0-9_]+$/, "Invalid trajectory ID format"),
|
|
155
163
|
version: z.literal(1),
|
|
156
164
|
task: TaskReferenceSchema,
|
|
157
165
|
status: TrajectoryStatusSchema,
|
|
@@ -160,10 +168,11 @@ var TrajectorySchema = z.object({
|
|
|
160
168
|
agents: z.array(AgentParticipationSchema),
|
|
161
169
|
chapters: z.array(ChapterSchema),
|
|
162
170
|
retrospective: RetrospectiveSchema.optional(),
|
|
163
|
-
commits: z.array(z.string()),
|
|
164
|
-
filesChanged: z.array(z.string()),
|
|
165
|
-
projectId: z.string(),
|
|
166
|
-
|
|
171
|
+
commits: z.array(z.string()).default([]),
|
|
172
|
+
filesChanged: z.array(z.string()).default([]),
|
|
173
|
+
projectId: z.string().optional(),
|
|
174
|
+
workflowId: z.string().optional(),
|
|
175
|
+
tags: z.array(z.string()).default([]),
|
|
167
176
|
_trace: TrajectoryTraceRefSchema.optional()
|
|
168
177
|
});
|
|
169
178
|
var CreateTrajectoryInputSchema = z.object({
|
|
@@ -696,11 +705,129 @@ var FileStorage = class {
|
|
|
696
705
|
trajectories: {}
|
|
697
706
|
});
|
|
698
707
|
}
|
|
708
|
+
await this.reconcileIndex();
|
|
709
|
+
}
|
|
710
|
+
/**
|
|
711
|
+
* Scan active/ and completed/ recursively and add any trajectory files
|
|
712
|
+
* missing from the index. Existing entries are preserved — reconcile
|
|
713
|
+
* only adds, never removes.
|
|
714
|
+
*
|
|
715
|
+
* Handles three on-disk layouts in completed/:
|
|
716
|
+
* - flat: completed/{id}.json (legacy workforce data)
|
|
717
|
+
* - monthly: completed/YYYY-MM/{id}.json (current save() writes)
|
|
718
|
+
* - nested: completed/.../{id}.json (defensive — any depth)
|
|
719
|
+
*
|
|
720
|
+
* Returns a ReconcileSummary so tests and CLI wrappers can observe
|
|
721
|
+
* outcomes without parsing logs. Only writes the index if anything was
|
|
722
|
+
* added.
|
|
723
|
+
*/
|
|
724
|
+
async reconcileIndex() {
|
|
725
|
+
const summary = {
|
|
726
|
+
scanned: 0,
|
|
727
|
+
added: 0,
|
|
728
|
+
alreadyIndexed: 0,
|
|
729
|
+
skippedMalformedJson: 0,
|
|
730
|
+
skippedSchemaViolation: 0,
|
|
731
|
+
skippedIoError: 0
|
|
732
|
+
};
|
|
733
|
+
const index = await this.loadIndex();
|
|
734
|
+
const before = Object.keys(index.trajectories).length;
|
|
735
|
+
const discovered = [];
|
|
736
|
+
try {
|
|
737
|
+
const activeFiles = await readdir(this.activeDir);
|
|
738
|
+
for (const file of activeFiles) {
|
|
739
|
+
if (!file.endsWith(".json")) continue;
|
|
740
|
+
discovered.push(join(this.activeDir, file));
|
|
741
|
+
}
|
|
742
|
+
} catch (error) {
|
|
743
|
+
if (error.code !== "ENOENT") throw error;
|
|
744
|
+
}
|
|
745
|
+
await this.walkJsonFilesInto(this.completedDir, discovered);
|
|
746
|
+
for (const filePath of discovered) {
|
|
747
|
+
summary.scanned += 1;
|
|
748
|
+
const result = await this.readTrajectoryFile(filePath);
|
|
749
|
+
if (!result.ok) {
|
|
750
|
+
if (result.reason === "malformed_json") {
|
|
751
|
+
summary.skippedMalformedJson += 1;
|
|
752
|
+
} else if (result.reason === "schema_violation") {
|
|
753
|
+
summary.skippedSchemaViolation += 1;
|
|
754
|
+
} else {
|
|
755
|
+
summary.skippedIoError += 1;
|
|
756
|
+
}
|
|
757
|
+
continue;
|
|
758
|
+
}
|
|
759
|
+
const trajectory2 = result.trajectory;
|
|
760
|
+
if (index.trajectories[trajectory2.id]) {
|
|
761
|
+
summary.alreadyIndexed += 1;
|
|
762
|
+
continue;
|
|
763
|
+
}
|
|
764
|
+
index.trajectories[trajectory2.id] = {
|
|
765
|
+
title: trajectory2.task.title,
|
|
766
|
+
status: trajectory2.status,
|
|
767
|
+
startedAt: trajectory2.startedAt,
|
|
768
|
+
completedAt: trajectory2.completedAt,
|
|
769
|
+
path: filePath
|
|
770
|
+
};
|
|
771
|
+
summary.added += 1;
|
|
772
|
+
}
|
|
773
|
+
if (Object.keys(index.trajectories).length !== before) {
|
|
774
|
+
await this.saveIndex(index);
|
|
775
|
+
}
|
|
776
|
+
const hadSkips = summary.skippedMalformedJson + summary.skippedSchemaViolation + summary.skippedIoError > 0;
|
|
777
|
+
if (summary.added > 0 || hadSkips) {
|
|
778
|
+
const parts = [`reconciled ${summary.added}/${summary.scanned}`];
|
|
779
|
+
if (summary.skippedMalformedJson > 0) {
|
|
780
|
+
parts.push(`malformed: ${summary.skippedMalformedJson}`);
|
|
781
|
+
}
|
|
782
|
+
if (summary.skippedSchemaViolation > 0) {
|
|
783
|
+
parts.push(`invalid: ${summary.skippedSchemaViolation}`);
|
|
784
|
+
}
|
|
785
|
+
if (summary.skippedIoError > 0) {
|
|
786
|
+
parts.push(`io: ${summary.skippedIoError}`);
|
|
787
|
+
}
|
|
788
|
+
console.warn(`[trajectories] ${parts.join(", ")}`);
|
|
789
|
+
}
|
|
790
|
+
return summary;
|
|
699
791
|
}
|
|
700
792
|
/**
|
|
701
|
-
*
|
|
793
|
+
* Recursively collect all .json file paths under `dir` into `out`.
|
|
794
|
+
* Silently treats a missing directory as empty.
|
|
702
795
|
*/
|
|
703
|
-
async
|
|
796
|
+
async walkJsonFilesInto(dir, out) {
|
|
797
|
+
let entries;
|
|
798
|
+
try {
|
|
799
|
+
entries = await readdir(dir, { withFileTypes: true });
|
|
800
|
+
} catch (error) {
|
|
801
|
+
if (error.code === "ENOENT") return;
|
|
802
|
+
throw error;
|
|
803
|
+
}
|
|
804
|
+
for (const entry of entries) {
|
|
805
|
+
const entryPath = join(dir, entry.name);
|
|
806
|
+
if (entry.isDirectory()) {
|
|
807
|
+
await this.walkJsonFilesInto(entryPath, out);
|
|
808
|
+
} else if (entry.isFile() && entry.name.endsWith(".json")) {
|
|
809
|
+
out.push(entryPath);
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
/**
|
|
814
|
+
* Save a trajectory.
|
|
815
|
+
*
|
|
816
|
+
* Validates the input against the trajectory schema before touching
|
|
817
|
+
* disk. Closes the historical read/write asymmetry where save() would
|
|
818
|
+
* happily write data that the reader then rejected, producing files
|
|
819
|
+
* that could never be loaded back.
|
|
820
|
+
*/
|
|
821
|
+
async save(input) {
|
|
822
|
+
const validation = validateTrajectory(input);
|
|
823
|
+
if (!validation.success) {
|
|
824
|
+
const issues = validation.errors?.issues.map((issue) => {
|
|
825
|
+
const path = issue.path.length > 0 ? issue.path.join(".") : "root";
|
|
826
|
+
return `${path}: ${issue.message}`;
|
|
827
|
+
}).join("; ") ?? "unknown validation error";
|
|
828
|
+
throw new Error(`Cannot save invalid trajectory: ${issues}`);
|
|
829
|
+
}
|
|
830
|
+
const trajectory2 = validation.data;
|
|
704
831
|
const isCompleted = trajectory2.status === "completed" || trajectory2.status === "abandoned";
|
|
705
832
|
let filePath;
|
|
706
833
|
if (isCompleted) {
|
|
@@ -730,19 +857,23 @@ var FileStorage = class {
|
|
|
730
857
|
async get(id) {
|
|
731
858
|
const activePath = join(this.activeDir, `${id}.json`);
|
|
732
859
|
if (existsSync(activePath)) {
|
|
733
|
-
return this.
|
|
860
|
+
return this.readTrajectoryOrNull(activePath);
|
|
734
861
|
}
|
|
735
862
|
const index = await this.loadIndex();
|
|
736
863
|
const entry = index.trajectories[id];
|
|
737
864
|
if (entry?.path && existsSync(entry.path)) {
|
|
738
|
-
return this.
|
|
865
|
+
return this.readTrajectoryOrNull(entry.path);
|
|
739
866
|
}
|
|
740
867
|
try {
|
|
868
|
+
const flatPath = join(this.completedDir, `${id}.json`);
|
|
869
|
+
if (existsSync(flatPath)) {
|
|
870
|
+
return this.readTrajectoryOrNull(flatPath);
|
|
871
|
+
}
|
|
741
872
|
const months = await readdir(this.completedDir);
|
|
742
873
|
for (const month of months) {
|
|
743
874
|
const filePath = join(this.completedDir, month, `${id}.json`);
|
|
744
875
|
if (existsSync(filePath)) {
|
|
745
|
-
return this.
|
|
876
|
+
return this.readTrajectoryOrNull(filePath);
|
|
746
877
|
}
|
|
747
878
|
}
|
|
748
879
|
} catch (error) {
|
|
@@ -765,7 +896,7 @@ var FileStorage = class {
|
|
|
765
896
|
let mostRecent = null;
|
|
766
897
|
let mostRecentTime = 0;
|
|
767
898
|
for (const file of jsonFiles) {
|
|
768
|
-
const trajectory2 = await this.
|
|
899
|
+
const trajectory2 = await this.readTrajectoryOrNull(
|
|
769
900
|
join(this.activeDir, file)
|
|
770
901
|
);
|
|
771
902
|
if (trajectory2) {
|
|
@@ -893,20 +1024,44 @@ var FileStorage = class {
|
|
|
893
1024
|
async close() {
|
|
894
1025
|
}
|
|
895
1026
|
// Private helpers
|
|
1027
|
+
/**
|
|
1028
|
+
* Read a trajectory file and return a tagged result so callers can
|
|
1029
|
+
* distinguish missing files, malformed JSON, and schema violations.
|
|
1030
|
+
*
|
|
1031
|
+
* Does NOT log. Callers choose whether to warn, swallow, or throw.
|
|
1032
|
+
*/
|
|
896
1033
|
async readTrajectoryFile(path) {
|
|
1034
|
+
let content;
|
|
897
1035
|
try {
|
|
898
|
-
|
|
899
|
-
const data = JSON.parse(content);
|
|
900
|
-
const validation = validateTrajectory(data);
|
|
901
|
-
if (validation.success) {
|
|
902
|
-
return validation.data;
|
|
903
|
-
}
|
|
904
|
-
console.error(`Invalid trajectory at ${path}:`, validation.errors);
|
|
905
|
-
return null;
|
|
1036
|
+
content = await readFile(path, "utf-8");
|
|
906
1037
|
} catch (error) {
|
|
907
|
-
|
|
908
|
-
|
|
1038
|
+
return { ok: false, reason: "io_error", path, error };
|
|
1039
|
+
}
|
|
1040
|
+
let data;
|
|
1041
|
+
try {
|
|
1042
|
+
data = JSON.parse(content);
|
|
1043
|
+
} catch (error) {
|
|
1044
|
+
return { ok: false, reason: "malformed_json", path, error };
|
|
909
1045
|
}
|
|
1046
|
+
const validation = validateTrajectory(data);
|
|
1047
|
+
if (validation.success) {
|
|
1048
|
+
return { ok: true, trajectory: validation.data };
|
|
1049
|
+
}
|
|
1050
|
+
return {
|
|
1051
|
+
ok: false,
|
|
1052
|
+
reason: "schema_violation",
|
|
1053
|
+
path,
|
|
1054
|
+
error: validation.errors
|
|
1055
|
+
};
|
|
1056
|
+
}
|
|
1057
|
+
/**
|
|
1058
|
+
* Convenience wrapper for callers that only care whether they got a
|
|
1059
|
+
* trajectory. Returns null for any failure and writes nothing to the
|
|
1060
|
+
* console — so nothing leaks into test output or the CLI spinner.
|
|
1061
|
+
*/
|
|
1062
|
+
async readTrajectoryOrNull(path) {
|
|
1063
|
+
const result = await this.readTrajectoryFile(path);
|
|
1064
|
+
return result.ok ? result.trajectory : null;
|
|
910
1065
|
}
|
|
911
1066
|
async loadIndex() {
|
|
912
1067
|
try {
|
|
@@ -944,6 +1099,124 @@ var FileStorage = class {
|
|
|
944
1099
|
};
|
|
945
1100
|
|
|
946
1101
|
// src/sdk/client.ts
|
|
1102
|
+
var require2 = createRequire(import.meta.url);
|
|
1103
|
+
function normalizeOptionalString(value) {
|
|
1104
|
+
const normalized = value?.trim();
|
|
1105
|
+
return normalized ? normalized : void 0;
|
|
1106
|
+
}
|
|
1107
|
+
function normalizeAutoCompactOptions(autoCompact) {
|
|
1108
|
+
if (!autoCompact) {
|
|
1109
|
+
return false;
|
|
1110
|
+
}
|
|
1111
|
+
if (autoCompact === true) {
|
|
1112
|
+
return { mechanical: false, markdown: true };
|
|
1113
|
+
}
|
|
1114
|
+
return {
|
|
1115
|
+
mechanical: autoCompact.mechanical ?? false,
|
|
1116
|
+
markdown: autoCompact.markdown ?? true
|
|
1117
|
+
};
|
|
1118
|
+
}
|
|
1119
|
+
function resolveStartWorkflowId(options) {
|
|
1120
|
+
if (options !== void 0 && Object.prototype.hasOwnProperty.call(options, "workflowId")) {
|
|
1121
|
+
return normalizeOptionalString(options.workflowId);
|
|
1122
|
+
}
|
|
1123
|
+
return normalizeOptionalString(process.env.TRAJECTORIES_WORKFLOW_ID);
|
|
1124
|
+
}
|
|
1125
|
+
function resolveTrajectoryCliInvocation() {
|
|
1126
|
+
const explicitCli = normalizeOptionalString(process.env.TRAJECTORIES_CLI);
|
|
1127
|
+
if (explicitCli) {
|
|
1128
|
+
if (/\.(?:cjs|mjs|js)$/i.test(explicitCli)) {
|
|
1129
|
+
return { command: process.execPath, args: [explicitCli] };
|
|
1130
|
+
}
|
|
1131
|
+
return { command: explicitCli, args: [] };
|
|
1132
|
+
}
|
|
1133
|
+
try {
|
|
1134
|
+
const packageJsonPath = require2.resolve("agent-trajectories/package.json");
|
|
1135
|
+
const pkg = JSON.parse(
|
|
1136
|
+
readFileSync(packageJsonPath, "utf-8")
|
|
1137
|
+
);
|
|
1138
|
+
const binEntry = typeof pkg.bin === "string" ? pkg.bin : pkg.bin?.trail ?? (pkg.name ? pkg.bin?.[pkg.name] : void 0);
|
|
1139
|
+
if (binEntry) {
|
|
1140
|
+
const cliPath = resolvePath(dirname(packageJsonPath), binEntry);
|
|
1141
|
+
if (existsSync2(cliPath)) {
|
|
1142
|
+
return { command: process.execPath, args: [cliPath] };
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
} catch {
|
|
1146
|
+
}
|
|
1147
|
+
return { command: "trail", args: [] };
|
|
1148
|
+
}
|
|
1149
|
+
function parseCompactWorkflowOutput(stdout) {
|
|
1150
|
+
const compactedPath = stdout.match(
|
|
1151
|
+
/^\s*Compacted trajectory saved to:\s*(.+)$/m
|
|
1152
|
+
)?.[1];
|
|
1153
|
+
const markdownPath = stdout.match(
|
|
1154
|
+
/^\s*Markdown summary saved to:\s*(.+)$/m
|
|
1155
|
+
)?.[1];
|
|
1156
|
+
if (!compactedPath) {
|
|
1157
|
+
throw new Error("compactWorkflow failed: unable to parse compacted path");
|
|
1158
|
+
}
|
|
1159
|
+
return {
|
|
1160
|
+
compactedPath: compactedPath.trim(),
|
|
1161
|
+
...markdownPath ? { markdownPath: markdownPath.trim() } : {}
|
|
1162
|
+
};
|
|
1163
|
+
}
|
|
1164
|
+
async function compactWorkflow(workflowId, options) {
|
|
1165
|
+
const normalizedWorkflowId = normalizeOptionalString(workflowId);
|
|
1166
|
+
if (!normalizedWorkflowId) {
|
|
1167
|
+
throw new Error("compactWorkflow failed: workflowId is required");
|
|
1168
|
+
}
|
|
1169
|
+
const cli = resolveTrajectoryCliInvocation();
|
|
1170
|
+
const args = [
|
|
1171
|
+
...cli.args,
|
|
1172
|
+
"compact",
|
|
1173
|
+
"--workflow",
|
|
1174
|
+
normalizedWorkflowId,
|
|
1175
|
+
"--all"
|
|
1176
|
+
];
|
|
1177
|
+
if (options?.markdown) {
|
|
1178
|
+
args.push("--markdown");
|
|
1179
|
+
}
|
|
1180
|
+
if (options?.mechanical) {
|
|
1181
|
+
args.push("--mechanical");
|
|
1182
|
+
}
|
|
1183
|
+
return new Promise((resolve, reject) => {
|
|
1184
|
+
const child = spawn(cli.command, args, {
|
|
1185
|
+
cwd: options?.cwd,
|
|
1186
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
1187
|
+
});
|
|
1188
|
+
const stdoutChunks = [];
|
|
1189
|
+
let stderr = "";
|
|
1190
|
+
child.stdout.on("data", (chunk) => {
|
|
1191
|
+
stdoutChunks.push(Buffer.from(chunk));
|
|
1192
|
+
});
|
|
1193
|
+
child.stderr.on("data", (chunk) => {
|
|
1194
|
+
stderr += chunk.toString();
|
|
1195
|
+
process.stderr.write(chunk);
|
|
1196
|
+
});
|
|
1197
|
+
child.on("error", (error) => {
|
|
1198
|
+
reject(new Error(`compactWorkflow failed: ${error.message}`));
|
|
1199
|
+
});
|
|
1200
|
+
child.on("close", (code) => {
|
|
1201
|
+
if (code !== 0) {
|
|
1202
|
+
reject(
|
|
1203
|
+
new Error(
|
|
1204
|
+
`compactWorkflow failed: ${stderr.trim() || `exit code ${code}`}`
|
|
1205
|
+
)
|
|
1206
|
+
);
|
|
1207
|
+
return;
|
|
1208
|
+
}
|
|
1209
|
+
try {
|
|
1210
|
+
const stdout = Buffer.concat(stdoutChunks).toString("utf-8");
|
|
1211
|
+
resolve(parseCompactWorkflowOutput(stdout));
|
|
1212
|
+
} catch (error) {
|
|
1213
|
+
reject(
|
|
1214
|
+
error instanceof Error ? error : new Error("compactWorkflow failed: unable to parse CLI output")
|
|
1215
|
+
);
|
|
1216
|
+
}
|
|
1217
|
+
});
|
|
1218
|
+
});
|
|
1219
|
+
}
|
|
947
1220
|
var TrajectorySession = class {
|
|
948
1221
|
trajectory;
|
|
949
1222
|
client;
|
|
@@ -965,6 +1238,23 @@ var TrajectorySession = class {
|
|
|
965
1238
|
get id() {
|
|
966
1239
|
return this.trajectory.id;
|
|
967
1240
|
}
|
|
1241
|
+
async autoCompactIfConfigured() {
|
|
1242
|
+
const autoCompact = this.client.getAutoCompactOptions();
|
|
1243
|
+
if (!autoCompact || !this.trajectory.workflowId) {
|
|
1244
|
+
return;
|
|
1245
|
+
}
|
|
1246
|
+
try {
|
|
1247
|
+
await compactWorkflow(this.trajectory.workflowId, {
|
|
1248
|
+
...autoCompact,
|
|
1249
|
+
cwd: this.client.getAutoCompactCwd()
|
|
1250
|
+
});
|
|
1251
|
+
} catch (error) {
|
|
1252
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1253
|
+
console.error(
|
|
1254
|
+
`Warning: autoCompact failed for workflow ${this.trajectory.workflowId}: ${message}`
|
|
1255
|
+
);
|
|
1256
|
+
}
|
|
1257
|
+
}
|
|
968
1258
|
/**
|
|
969
1259
|
* Start a new chapter
|
|
970
1260
|
* @param title - Chapter title
|
|
@@ -1074,6 +1364,7 @@ var TrajectorySession = class {
|
|
|
1074
1364
|
async complete(input) {
|
|
1075
1365
|
this.trajectory = completeTrajectory(this.trajectory, input);
|
|
1076
1366
|
await this.client.save(this.trajectory);
|
|
1367
|
+
await this.autoCompactIfConfigured();
|
|
1077
1368
|
return this.trajectory;
|
|
1078
1369
|
}
|
|
1079
1370
|
/**
|
|
@@ -1139,11 +1430,21 @@ var TrajectoryClient = class {
|
|
|
1139
1430
|
defaultAgent;
|
|
1140
1431
|
projectId;
|
|
1141
1432
|
autoSave;
|
|
1433
|
+
autoCompactCwd;
|
|
1434
|
+
autoCompact;
|
|
1142
1435
|
constructor(options = {}) {
|
|
1143
1436
|
this.storage = options.storage ?? new FileStorage(options.dataDir);
|
|
1144
1437
|
this.defaultAgent = options.defaultAgent ?? process.env.TRAJECTORIES_AGENT;
|
|
1145
1438
|
this.projectId = options.projectId ?? process.env.TRAJECTORIES_PROJECT;
|
|
1146
1439
|
this.autoSave = options.autoSave ?? true;
|
|
1440
|
+
this.autoCompact = normalizeAutoCompactOptions(options.autoCompact);
|
|
1441
|
+
this.autoCompactCwd = options.storage ? void 0 : options.dataDir;
|
|
1442
|
+
}
|
|
1443
|
+
getAutoCompactOptions() {
|
|
1444
|
+
return this.autoCompact;
|
|
1445
|
+
}
|
|
1446
|
+
getAutoCompactCwd() {
|
|
1447
|
+
return this.autoCompactCwd;
|
|
1147
1448
|
}
|
|
1148
1449
|
/**
|
|
1149
1450
|
* Initialize the client (creates storage directories, etc.)
|
|
@@ -1183,13 +1484,16 @@ var TrajectoryClient = class {
|
|
|
1183
1484
|
"Complete or abandon the active trajectory first"
|
|
1184
1485
|
);
|
|
1185
1486
|
}
|
|
1487
|
+
const workflowId = resolveStartWorkflowId(options);
|
|
1488
|
+
const { workflowId: _workflowId, ...createOptions } = options ?? {};
|
|
1186
1489
|
const trajectory2 = createTrajectory({
|
|
1187
1490
|
title,
|
|
1188
1491
|
projectId: this.projectId,
|
|
1189
|
-
...
|
|
1492
|
+
...createOptions
|
|
1190
1493
|
});
|
|
1191
|
-
|
|
1192
|
-
|
|
1494
|
+
const stampedTrajectory = workflowId ? { ...trajectory2, workflowId } : trajectory2;
|
|
1495
|
+
await this.storage.save(stampedTrajectory);
|
|
1496
|
+
return new TrajectorySession(stampedTrajectory, this, this.autoSave);
|
|
1193
1497
|
}
|
|
1194
1498
|
/**
|
|
1195
1499
|
* Resume the currently active trajectory
|
|
@@ -1573,7 +1877,7 @@ function trajectory(title) {
|
|
|
1573
1877
|
|
|
1574
1878
|
// src/core/trailers.ts
|
|
1575
1879
|
import { execSync as execSync2 } from "child_process";
|
|
1576
|
-
import { readFileSync } from "fs";
|
|
1880
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
1577
1881
|
|
|
1578
1882
|
// src/core/trace.ts
|
|
1579
1883
|
import { execSync } from "child_process";
|
|
@@ -1615,7 +1919,7 @@ function parseTrajectoryFromMessage(commitMessage) {
|
|
|
1615
1919
|
const lines = commitMessage.split("\n");
|
|
1616
1920
|
for (const line of lines) {
|
|
1617
1921
|
const match = line.match(
|
|
1618
|
-
new RegExp(`^${TRAJECTORY_TRAILER_KEY}:\\s*(traj_[a-z0-
|
|
1922
|
+
new RegExp(`^${TRAJECTORY_TRAILER_KEY}:\\s*(traj_[a-z0-9_]+)$`)
|
|
1619
1923
|
);
|
|
1620
1924
|
if (match) {
|
|
1621
1925
|
return match[1];
|
|
@@ -1717,6 +2021,7 @@ export {
|
|
|
1717
2021
|
exportToPRSummary,
|
|
1718
2022
|
exportToTimeline,
|
|
1719
2023
|
FileStorage,
|
|
2024
|
+
compactWorkflow,
|
|
1720
2025
|
TrajectorySession,
|
|
1721
2026
|
TrajectoryClient,
|
|
1722
2027
|
TrajectoryBuilder,
|
|
@@ -1728,4 +2033,4 @@ export {
|
|
|
1728
2033
|
getCommitsBetween,
|
|
1729
2034
|
getFilesChangedBetween
|
|
1730
2035
|
};
|
|
1731
|
-
//# sourceMappingURL=chunk-
|
|
2036
|
+
//# sourceMappingURL=chunk-W222QB6V.js.map
|