aicodeman 1.25.0 → 1.26.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent-case-marker.d.ts +91 -0
- package/dist/agent-case-marker.d.ts.map +1 -0
- package/dist/agent-case-marker.js +151 -0
- package/dist/agent-case-marker.js.map +1 -0
- package/dist/codex-transcript.d.ts +84 -0
- package/dist/codex-transcript.d.ts.map +1 -0
- package/dist/codex-transcript.js +341 -0
- package/dist/codex-transcript.js.map +1 -0
- package/dist/config/cli-registry/schema.d.ts +4 -0
- package/dist/config/cli-registry/schema.d.ts.map +1 -1
- package/dist/config/cli-registry/schema.js +15 -1
- package/dist/config/cli-registry/schema.js.map +1 -1
- package/dist/config/cli-registry/stock.d.ts.map +1 -1
- package/dist/config/cli-registry/stock.js +12 -0
- package/dist/config/cli-registry/stock.js.map +1 -1
- package/dist/config/cli-registry/types.d.ts +23 -0
- package/dist/config/cli-registry/types.d.ts.map +1 -1
- package/dist/hooks-config.d.ts +25 -0
- package/dist/hooks-config.d.ts.map +1 -1
- package/dist/hooks-config.js +67 -3
- package/dist/hooks-config.js.map +1 -1
- package/dist/services/unified-session-service.d.ts +28 -10
- package/dist/services/unified-session-service.d.ts.map +1 -1
- package/dist/services/unified-session-service.js +11 -6
- package/dist/services/unified-session-service.js.map +1 -1
- package/dist/session.d.ts +11 -0
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +90 -41
- package/dist/session.js.map +1 -1
- package/dist/types/api.d.ts +32 -0
- package/dist/types/api.d.ts.map +1 -1
- package/dist/types/api.js.map +1 -1
- package/dist/web/public/admin-ui.js.gz +0 -0
- package/dist/web/public/api-client.c9b1cddc.js.gz +0 -0
- package/dist/web/public/app.3a89ac57.js.gz +0 -0
- package/dist/web/public/approvals-ui.js.gz +0 -0
- package/dist/web/public/constants.7a635e34.js.gz +0 -0
- package/dist/web/public/cron-ui.js.gz +0 -0
- package/dist/web/public/entrance-animations.js.gz +0 -0
- package/dist/web/public/home-sessions.js.gz +0 -0
- package/dist/web/public/i18n.9db8c4e0.js.gz +0 -0
- package/dist/web/public/image-input.ee16ad88.js.gz +0 -0
- package/dist/web/public/index.html +4 -4
- package/dist/web/public/index.html.br +0 -0
- package/dist/web/public/index.html.gz +0 -0
- package/dist/web/public/input-cjk.87f14251.js.gz +0 -0
- package/dist/web/public/keyboard-accessory.daf18302.js.gz +0 -0
- package/dist/web/public/mobile-handlers.0f83a608.js.gz +0 -0
- package/dist/web/public/mobile-overview.js +12 -1
- package/dist/web/public/mobile-overview.js.br +0 -0
- package/dist/web/public/mobile-overview.js.gz +0 -0
- package/dist/web/public/mobile.7112f27d.css.gz +0 -0
- package/dist/web/public/notification-manager.36ea4624.js.gz +0 -0
- package/dist/web/public/orchestrator-panel.js.gz +0 -0
- package/dist/web/public/{panels-ui.db4785bf.js → panels-ui.9eb5b235.js} +1 -1
- package/dist/web/public/panels-ui.9eb5b235.js.br +0 -0
- package/dist/web/public/panels-ui.9eb5b235.js.gz +0 -0
- package/dist/web/public/ralph-panel.6de2d0f8.js.gz +0 -0
- package/dist/web/public/ralph-wizard.13a1831e.js.gz +0 -0
- package/dist/web/public/readmymind-ui.js.gz +0 -0
- package/dist/web/public/respawn-ui.ff0dae4c.js.gz +0 -0
- package/dist/web/public/sanitize-html.bc7078d6.js.gz +0 -0
- package/dist/web/public/session-lineage.js.gz +0 -0
- package/dist/web/public/{session-ui.58116fce.js → session-ui.cd222710.js} +32 -23
- package/dist/web/public/session-ui.cd222710.js.br +0 -0
- package/dist/web/public/session-ui.cd222710.js.gz +0 -0
- package/dist/web/public/settings-ui.554f9cdd.js.gz +0 -0
- package/dist/web/public/styles.298f81f2.css +1 -0
- package/dist/web/public/styles.298f81f2.css.br +0 -0
- package/dist/web/public/{styles.2a35729d.css.gz → styles.298f81f2.css.gz} +0 -0
- package/dist/web/public/subagent-windows.e6ca799f.js.gz +0 -0
- package/dist/web/public/sw.js.gz +0 -0
- package/dist/web/public/tab-rail-resize.42c24949.js.gz +0 -0
- package/dist/web/public/{terminal-ui.70445f81.js → terminal-ui.a39b5aa7.js} +2 -2
- package/dist/web/public/terminal-ui.a39b5aa7.js.br +0 -0
- package/dist/web/public/terminal-ui.a39b5aa7.js.gz +0 -0
- package/dist/web/public/ultracode-panel.js.gz +0 -0
- package/dist/web/public/ultracode-windows.js.gz +0 -0
- package/dist/web/public/upload.html.gz +0 -0
- package/dist/web/public/vendor/dompurify.min.js.gz +0 -0
- package/dist/web/public/vendor/marked.min.js.gz +0 -0
- package/dist/web/public/vendor/xterm-addon-fit.min.js.gz +0 -0
- package/dist/web/public/vendor/xterm-addon-serialize.min.js.gz +0 -0
- package/dist/web/public/vendor/xterm-addon-unicode11.min.js.gz +0 -0
- package/dist/web/public/vendor/xterm-addon-webgl.min.js.gz +0 -0
- package/dist/web/public/vendor/xterm-predictive-echo.bd6882b8.js.gz +0 -0
- package/dist/web/public/vendor/xterm-zerolag-input.6fee72f2.js.gz +0 -0
- package/dist/web/public/vendor/xterm.css.gz +0 -0
- package/dist/web/public/vendor/xterm.min.js.gz +0 -0
- package/dist/web/public/voice-input.c4b51eb6.js.gz +0 -0
- package/dist/web/public/voice-pcm-worklet.js.gz +0 -0
- package/dist/web/public/webview-tabs.js.gz +0 -0
- package/dist/web/route-helpers.d.ts +18 -0
- package/dist/web/route-helpers.d.ts.map +1 -1
- package/dist/web/route-helpers.js +23 -0
- package/dist/web/route-helpers.js.map +1 -1
- package/dist/web/routes/case-routes.d.ts.map +1 -1
- package/dist/web/routes/case-routes.js +73 -2
- package/dist/web/routes/case-routes.js.map +1 -1
- package/dist/web/routes/session-routes.d.ts.map +1 -1
- package/dist/web/routes/session-routes.js +76 -4
- package/dist/web/routes/session-routes.js.map +1 -1
- package/dist/web/schemas.d.ts +1 -0
- package/dist/web/schemas.d.ts.map +1 -1
- package/dist/web/schemas.js +10 -0
- package/dist/web/schemas.js.map +1 -1
- package/dist/web/server.d.ts.map +1 -1
- package/dist/web/server.js +20 -1
- package/dist/web/server.js.map +1 -1
- package/package.json +1 -1
- package/skills/codeman/SKILL.md +14 -10
- package/skills/codeman/preamble.sh +6 -3
- package/skills/codeman/reference/endpoints.md +9 -0
- package/skills/codeman/reference/recipes.md +1 -1
- package/skills/codeman/reference/verbs.md +15 -0
- package/dist/web/public/panels-ui.db4785bf.js.br +0 -0
- package/dist/web/public/panels-ui.db4785bf.js.gz +0 -0
- package/dist/web/public/session-ui.58116fce.js.br +0 -0
- package/dist/web/public/session-ui.58116fce.js.gz +0 -0
- package/dist/web/public/styles.2a35729d.css +0 -1
- package/dist/web/public/styles.2a35729d.css.br +0 -0
- package/dist/web/public/terminal-ui.70445f81.js.br +0 -0
- package/dist/web/public/terminal-ui.70445f81.js.gz +0 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview The marker file that records a case directory as one Codeman scaffolded
|
|
3
|
+
* FOR an agent-spawned session, so scratch worker workspaces can be told apart from the
|
|
4
|
+
* user's real projects long after the sessions that created them are gone.
|
|
5
|
+
*
|
|
6
|
+
* Why a file in the case directory rather than a central registry in `~/.codeman`:
|
|
7
|
+
* the thing being labelled is a directory on the user's disk, and the label has to
|
|
8
|
+
* survive everything that can happen to Codeman's own state (a wiped data dir, a
|
|
9
|
+
* different instance, a hand-moved case). A registry would also need stale-entry
|
|
10
|
+
* pruning and owner scoping of its own, while a marker is deleted by the same `rm -rf`
|
|
11
|
+
* that deletes the case, and is discoverable by a user who just runs `ls -a`.
|
|
12
|
+
*
|
|
13
|
+
* ⚠️ Written ONLY on the path that CREATES the directory (`POST /api/quick-start`'s
|
|
14
|
+
* `!existsSync` branch). A linked case, a cloned repo, a git worktree or any other
|
|
15
|
+
* pre-existing directory must never be labelled agent-created: the label drives a
|
|
16
|
+
* cleanup affordance, and mislabelling someone's repo there is the one failure mode
|
|
17
|
+
* that costs real work. `POST /api/sessions` takes an existing `workingDir` and so
|
|
18
|
+
* writes no marker at all, by construction.
|
|
19
|
+
*
|
|
20
|
+
* ⚠️ Reading is strict and total: anything that does not parse as a version-1 marker
|
|
21
|
+
* (truncated write, hand-edited junk, a user's unrelated file of the same name) reads
|
|
22
|
+
* as "not agent-created" rather than as a partially-trusted entry. A marker is
|
|
23
|
+
* metadata; deleting the file is the supported way to adopt a scratch case as a real
|
|
24
|
+
* one, which is what the `note` field written into it tells the user.
|
|
25
|
+
*/
|
|
26
|
+
/** Marker filename inside the case directory. Dot-prefixed so it stays out of the way. */
|
|
27
|
+
export declare const AGENT_CASE_MARKER_FILE = ".codeman-agent-case.json";
|
|
28
|
+
/** Current marker schema version. A marker of any other version reads as absent. */
|
|
29
|
+
export declare const AGENT_CASE_MARKER_VERSION = 1;
|
|
30
|
+
/**
|
|
31
|
+
* Origin recorded when a create request carried a resolvable spawning session but no
|
|
32
|
+
* explicit origin of its own (an agent driving the API by hand, or an older copy of
|
|
33
|
+
* the skill). Nothing in the browser UI sets lineage, so this really does mean "another
|
|
34
|
+
* session spawned this", not "a human clicked Run".
|
|
35
|
+
*/
|
|
36
|
+
export declare const AGENT_ORIGIN_SPAWNED_BY_SESSION = "agent-session";
|
|
37
|
+
/** Origin the packaged agent skill sends on its shared curl invocation. */
|
|
38
|
+
export declare const AGENT_ORIGIN_CODEMAN_SKILL = "codeman-skill";
|
|
39
|
+
/**
|
|
40
|
+
* What a case directory records about the agent spawn that created it.
|
|
41
|
+
* Every field beyond `version`/`createdAt`/`createdBy` is decoration for the cleanup UI.
|
|
42
|
+
*/
|
|
43
|
+
export interface AgentCaseMarker {
|
|
44
|
+
version: typeof AGENT_CASE_MARKER_VERSION;
|
|
45
|
+
/** ISO timestamp of the spawn that created the directory. */
|
|
46
|
+
createdAt: string;
|
|
47
|
+
/** Who asked: `codeman-skill`, `agent-session`, or another caller's own token. */
|
|
48
|
+
createdBy: string;
|
|
49
|
+
/** Full id of the session that spawned the worker, when one resolved. */
|
|
50
|
+
parentSessionId?: string;
|
|
51
|
+
/** That session's display name at spawn time, so the user recognises it later. */
|
|
52
|
+
parentSessionName?: string;
|
|
53
|
+
/** Run mode the worker was started in (`claude`, `deepseek`, …). */
|
|
54
|
+
mode?: string;
|
|
55
|
+
/** Owner the case was created for, in multi-user mode. */
|
|
56
|
+
owner?: string;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Validate an origin token coming off the wire (`agentOrigin` body field or the
|
|
60
|
+
* `X-Codeman-Agent-Origin` header). Returns `undefined` for anything that is not a
|
|
61
|
+
* short lowercase token — the value reaches the UI and a JSON file, so it is
|
|
62
|
+
* allowlisted rather than escaped at each use.
|
|
63
|
+
*/
|
|
64
|
+
export declare function normalizeAgentOrigin(raw: unknown): string | undefined;
|
|
65
|
+
/**
|
|
66
|
+
* Build a marker from a spawn's details. Pure, so the route can hand it straight to
|
|
67
|
+
* the writer and the tests can assert on the shape without touching a disk.
|
|
68
|
+
*/
|
|
69
|
+
export declare function buildAgentCaseMarker(input: {
|
|
70
|
+
createdBy: string;
|
|
71
|
+
createdAt?: Date;
|
|
72
|
+
parentSessionId?: string;
|
|
73
|
+
parentSessionName?: string;
|
|
74
|
+
mode?: string;
|
|
75
|
+
owner?: string;
|
|
76
|
+
}): AgentCaseMarker;
|
|
77
|
+
/**
|
|
78
|
+
* Parse marker JSON. Returns `null` for anything that is not a well-formed version-1
|
|
79
|
+
* marker, including a valid-JSON object of the wrong shape — see the strictness note
|
|
80
|
+
* in the file header.
|
|
81
|
+
*/
|
|
82
|
+
export declare function parseAgentCaseMarker(raw: string): AgentCaseMarker | null;
|
|
83
|
+
/**
|
|
84
|
+
* Write the marker into `casePath`. Best-effort by design: the marker is metadata for
|
|
85
|
+
* a later cleanup, and a failed write must never fail the worker spawn that is the
|
|
86
|
+
* point of the request. Returns whether it landed.
|
|
87
|
+
*/
|
|
88
|
+
export declare function writeAgentCaseMarker(casePath: string, marker: AgentCaseMarker): Promise<boolean>;
|
|
89
|
+
/** Read the marker out of `casePath`, or `null` if there isn't a valid one. */
|
|
90
|
+
export declare function readAgentCaseMarker(casePath: string): Promise<AgentCaseMarker | null>;
|
|
91
|
+
//# sourceMappingURL=agent-case-marker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-case-marker.d.ts","sourceRoot":"","sources":["../src/agent-case-marker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAKH,0FAA0F;AAC1F,eAAO,MAAM,sBAAsB,6BAA6B,CAAC;AAEjE,oFAAoF;AACpF,eAAO,MAAM,yBAAyB,IAAI,CAAC;AAE3C;;;;;GAKG;AACH,eAAO,MAAM,+BAA+B,kBAAkB,CAAC;AAE/D,2EAA2E;AAC3E,eAAO,MAAM,0BAA0B,kBAAkB,CAAC;AAiB1D;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,yBAAyB,CAAC;IAC1C,6DAA6D;IAC7D,SAAS,EAAE,MAAM,CAAC;IAClB,kFAAkF;IAClF,SAAS,EAAE,MAAM,CAAC;IAClB,yEAAyE;IACzE,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,kFAAkF;IAClF,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,oEAAoE;IACpE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,0DAA0D;IAC1D,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAKrE;AASD;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE;IAC1C,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,IAAI,CAAC;IACjB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,eAAe,CAelB;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CAwBxE;AAED;;;;GAIG;AACH,wBAAsB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,OAAO,CAAC,CAQtG;AAED,+EAA+E;AAC/E,wBAAsB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAM3F"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview The marker file that records a case directory as one Codeman scaffolded
|
|
3
|
+
* FOR an agent-spawned session, so scratch worker workspaces can be told apart from the
|
|
4
|
+
* user's real projects long after the sessions that created them are gone.
|
|
5
|
+
*
|
|
6
|
+
* Why a file in the case directory rather than a central registry in `~/.codeman`:
|
|
7
|
+
* the thing being labelled is a directory on the user's disk, and the label has to
|
|
8
|
+
* survive everything that can happen to Codeman's own state (a wiped data dir, a
|
|
9
|
+
* different instance, a hand-moved case). A registry would also need stale-entry
|
|
10
|
+
* pruning and owner scoping of its own, while a marker is deleted by the same `rm -rf`
|
|
11
|
+
* that deletes the case, and is discoverable by a user who just runs `ls -a`.
|
|
12
|
+
*
|
|
13
|
+
* ⚠️ Written ONLY on the path that CREATES the directory (`POST /api/quick-start`'s
|
|
14
|
+
* `!existsSync` branch). A linked case, a cloned repo, a git worktree or any other
|
|
15
|
+
* pre-existing directory must never be labelled agent-created: the label drives a
|
|
16
|
+
* cleanup affordance, and mislabelling someone's repo there is the one failure mode
|
|
17
|
+
* that costs real work. `POST /api/sessions` takes an existing `workingDir` and so
|
|
18
|
+
* writes no marker at all, by construction.
|
|
19
|
+
*
|
|
20
|
+
* ⚠️ Reading is strict and total: anything that does not parse as a version-1 marker
|
|
21
|
+
* (truncated write, hand-edited junk, a user's unrelated file of the same name) reads
|
|
22
|
+
* as "not agent-created" rather than as a partially-trusted entry. A marker is
|
|
23
|
+
* metadata; deleting the file is the supported way to adopt a scratch case as a real
|
|
24
|
+
* one, which is what the `note` field written into it tells the user.
|
|
25
|
+
*/
|
|
26
|
+
import { readFile, writeFile } from 'node:fs/promises';
|
|
27
|
+
import { join } from 'node:path';
|
|
28
|
+
/** Marker filename inside the case directory. Dot-prefixed so it stays out of the way. */
|
|
29
|
+
export const AGENT_CASE_MARKER_FILE = '.codeman-agent-case.json';
|
|
30
|
+
/** Current marker schema version. A marker of any other version reads as absent. */
|
|
31
|
+
export const AGENT_CASE_MARKER_VERSION = 1;
|
|
32
|
+
/**
|
|
33
|
+
* Origin recorded when a create request carried a resolvable spawning session but no
|
|
34
|
+
* explicit origin of its own (an agent driving the API by hand, or an older copy of
|
|
35
|
+
* the skill). Nothing in the browser UI sets lineage, so this really does mean "another
|
|
36
|
+
* session spawned this", not "a human clicked Run".
|
|
37
|
+
*/
|
|
38
|
+
export const AGENT_ORIGIN_SPAWNED_BY_SESSION = 'agent-session';
|
|
39
|
+
/** Origin the packaged agent skill sends on its shared curl invocation. */
|
|
40
|
+
export const AGENT_ORIGIN_CODEMAN_SKILL = 'codeman-skill';
|
|
41
|
+
/** Longest accepted origin token (the value is echoed into the UI and the marker). */
|
|
42
|
+
const MAX_ORIGIN_LENGTH = 32;
|
|
43
|
+
/** Longest accepted free-text field read back out of a marker. */
|
|
44
|
+
const MAX_MARKER_FIELD_LENGTH = 200;
|
|
45
|
+
/** Lowercase token: what an origin may look like on the wire and on disk. */
|
|
46
|
+
const AGENT_ORIGIN_PATTERN = /^[a-z0-9][a-z0-9._-]*$/;
|
|
47
|
+
/** Explains the file to whoever finds it in their case directory. */
|
|
48
|
+
const MARKER_NOTE = 'Created by a Codeman agent worker (see the Manage tab in Add Case). ' +
|
|
49
|
+
'Delete this file to keep the case out of the agent-case cleanup list; ' +
|
|
50
|
+
'deleting the whole directory removes the case.';
|
|
51
|
+
/**
|
|
52
|
+
* Validate an origin token coming off the wire (`agentOrigin` body field or the
|
|
53
|
+
* `X-Codeman-Agent-Origin` header). Returns `undefined` for anything that is not a
|
|
54
|
+
* short lowercase token — the value reaches the UI and a JSON file, so it is
|
|
55
|
+
* allowlisted rather than escaped at each use.
|
|
56
|
+
*/
|
|
57
|
+
export function normalizeAgentOrigin(raw) {
|
|
58
|
+
if (typeof raw !== 'string')
|
|
59
|
+
return undefined;
|
|
60
|
+
const value = raw.trim().toLowerCase();
|
|
61
|
+
if (!value || value.length > MAX_ORIGIN_LENGTH)
|
|
62
|
+
return undefined;
|
|
63
|
+
return AGENT_ORIGIN_PATTERN.test(value) ? value : undefined;
|
|
64
|
+
}
|
|
65
|
+
/** Trim an optional free-text marker field to something safe to store and render. */
|
|
66
|
+
function normalizeField(raw) {
|
|
67
|
+
if (typeof raw !== 'string')
|
|
68
|
+
return undefined;
|
|
69
|
+
const value = raw.trim();
|
|
70
|
+
return value ? value.slice(0, MAX_MARKER_FIELD_LENGTH) : undefined;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Build a marker from a spawn's details. Pure, so the route can hand it straight to
|
|
74
|
+
* the writer and the tests can assert on the shape without touching a disk.
|
|
75
|
+
*/
|
|
76
|
+
export function buildAgentCaseMarker(input) {
|
|
77
|
+
const marker = {
|
|
78
|
+
version: AGENT_CASE_MARKER_VERSION,
|
|
79
|
+
createdAt: (input.createdAt ?? new Date()).toISOString(),
|
|
80
|
+
createdBy: normalizeAgentOrigin(input.createdBy) ?? AGENT_ORIGIN_SPAWNED_BY_SESSION,
|
|
81
|
+
};
|
|
82
|
+
const parentSessionId = normalizeField(input.parentSessionId);
|
|
83
|
+
const parentSessionName = normalizeField(input.parentSessionName);
|
|
84
|
+
const mode = normalizeField(input.mode);
|
|
85
|
+
const owner = normalizeField(input.owner);
|
|
86
|
+
if (parentSessionId)
|
|
87
|
+
marker.parentSessionId = parentSessionId;
|
|
88
|
+
if (parentSessionName)
|
|
89
|
+
marker.parentSessionName = parentSessionName;
|
|
90
|
+
if (mode)
|
|
91
|
+
marker.mode = mode;
|
|
92
|
+
if (owner)
|
|
93
|
+
marker.owner = owner;
|
|
94
|
+
return marker;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Parse marker JSON. Returns `null` for anything that is not a well-formed version-1
|
|
98
|
+
* marker, including a valid-JSON object of the wrong shape — see the strictness note
|
|
99
|
+
* in the file header.
|
|
100
|
+
*/
|
|
101
|
+
export function parseAgentCaseMarker(raw) {
|
|
102
|
+
let value;
|
|
103
|
+
try {
|
|
104
|
+
value = JSON.parse(raw);
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
110
|
+
return null;
|
|
111
|
+
const record = value;
|
|
112
|
+
if (record.version !== AGENT_CASE_MARKER_VERSION)
|
|
113
|
+
return null;
|
|
114
|
+
const createdAt = normalizeField(record.createdAt);
|
|
115
|
+
const createdBy = normalizeAgentOrigin(record.createdBy);
|
|
116
|
+
if (!createdAt || !createdBy || Number.isNaN(Date.parse(createdAt)))
|
|
117
|
+
return null;
|
|
118
|
+
return buildAgentCaseMarker({
|
|
119
|
+
createdBy,
|
|
120
|
+
createdAt: new Date(createdAt),
|
|
121
|
+
parentSessionId: normalizeField(record.parentSessionId),
|
|
122
|
+
parentSessionName: normalizeField(record.parentSessionName),
|
|
123
|
+
mode: normalizeField(record.mode),
|
|
124
|
+
owner: normalizeField(record.owner),
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Write the marker into `casePath`. Best-effort by design: the marker is metadata for
|
|
129
|
+
* a later cleanup, and a failed write must never fail the worker spawn that is the
|
|
130
|
+
* point of the request. Returns whether it landed.
|
|
131
|
+
*/
|
|
132
|
+
export async function writeAgentCaseMarker(casePath, marker) {
|
|
133
|
+
try {
|
|
134
|
+
const body = JSON.stringify({ ...marker, note: MARKER_NOTE }, null, 2);
|
|
135
|
+
await writeFile(join(casePath, AGENT_CASE_MARKER_FILE), `${body}\n`, 'utf-8');
|
|
136
|
+
return true;
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
/** Read the marker out of `casePath`, or `null` if there isn't a valid one. */
|
|
143
|
+
export async function readAgentCaseMarker(casePath) {
|
|
144
|
+
try {
|
|
145
|
+
return parseAgentCaseMarker(await readFile(join(casePath, AGENT_CASE_MARKER_FILE), 'utf-8'));
|
|
146
|
+
}
|
|
147
|
+
catch {
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=agent-case-marker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-case-marker.js","sourceRoot":"","sources":["../src/agent-case-marker.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Scan `~/.codex/sessions/<yyyy>/<mm>/<dd>/rollout-*.jsonl` for Past
|
|
3
|
+
* Sessions rows, the codex analog of what `scanOmpSessionsHistory()`
|
|
4
|
+
* (omp-transcript.ts) does for omp and `scanProjectDir()` (session-routes.ts)
|
|
5
|
+
* does for Claude's own `~/.claude/projects` transcripts.
|
|
6
|
+
*
|
|
7
|
+
* Without this a codex conversation is invisible to Codeman the moment its
|
|
8
|
+
* session record goes away, even though codex itself never forgot it: the
|
|
9
|
+
* unified list is built from `~/.claude/projects` plus omp's own store, and
|
|
10
|
+
* codex writes to neither. A user who wanted to pick a codex thread back up had
|
|
11
|
+
* to find its id by hand and pass `codexConfig.resumeSessionId` to the API.
|
|
12
|
+
*
|
|
13
|
+
* ## Why this reads windows rather than whole files
|
|
14
|
+
*
|
|
15
|
+
* An omp session file is the conversation only, so its scanner reads each file
|
|
16
|
+
* whole. A codex rollout is not comparable: it carries every reasoning block and
|
|
17
|
+
* every tool call, and its `session_meta` line alone embeds the full base
|
|
18
|
+
* instructions. Measured on a real store of 519 rollouts, the median file is
|
|
19
|
+
* 407 KiB, the 90th percentile 1.3 MiB and the largest 25 MiB, for 381 MiB in
|
|
20
|
+
* total. So this reads a head window for the identity and the opening prompt,
|
|
21
|
+
* and a tail window for the most recent one.
|
|
22
|
+
*
|
|
23
|
+
* The head budget is 128 KiB because `session_meta` runs to roughly 19 KiB and
|
|
24
|
+
* the first real user message lands near 69 KiB behind it, both measured on
|
|
25
|
+
* codex 0.152.1.
|
|
26
|
+
*
|
|
27
|
+
* ## Where the prompt text comes from
|
|
28
|
+
*
|
|
29
|
+
* Codex has emitted user input under three shapes, and this reads all of them,
|
|
30
|
+
* preferring the ones that carry real input only:
|
|
31
|
+
*
|
|
32
|
+
* - `event_msg` / `item_completed` with an `item.type` of `UserMessage`, which
|
|
33
|
+
* is what codex 0.152.1 writes.
|
|
34
|
+
* - `event_msg` / `user_message`, which older versions wrote.
|
|
35
|
+
* - `response_item` rows with `role: 'user'`, the last resort. These mix real
|
|
36
|
+
* input with injected context (AGENTS.md, environment context, compaction
|
|
37
|
+
* summaries), so they are read only when neither shape above appears, and
|
|
38
|
+
* the obvious injections are dropped.
|
|
39
|
+
*
|
|
40
|
+
* @module codex-transcript
|
|
41
|
+
*/
|
|
42
|
+
export interface CodexHistorySession {
|
|
43
|
+
/** The rollout's own thread id — the token `codex resume <id>` expects. */
|
|
44
|
+
sessionId: string;
|
|
45
|
+
/**
|
|
46
|
+
* `session_meta.originator`, which codex stamps from
|
|
47
|
+
* CODEX_INTERNAL_ORIGINATOR_OVERRIDE — `codeman_<sessionId>` for every pane
|
|
48
|
+
* Codeman spawns. The only link between a FRESH codex pane and the rollout it
|
|
49
|
+
* is writing, since such a pane knows no thread id of its own.
|
|
50
|
+
*/
|
|
51
|
+
originator?: string;
|
|
52
|
+
workingDir: string;
|
|
53
|
+
sizeBytes: number;
|
|
54
|
+
/** ISO timestamp, from the file's own mtime. */
|
|
55
|
+
lastModified: string;
|
|
56
|
+
firstPrompt?: string;
|
|
57
|
+
lastPrompt?: string;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Codex conversations on this host, newest first, for the unified session list.
|
|
61
|
+
*
|
|
62
|
+
* Sub-agent threads are left out: codex spawns them for itself, they are not
|
|
63
|
+
* something a person picks back up, and on a real store they outnumber the
|
|
64
|
+
* threads that are.
|
|
65
|
+
*/
|
|
66
|
+
export declare function scanCodexSessionsHistory(): Promise<CodexHistorySession[]>;
|
|
67
|
+
/**
|
|
68
|
+
* Which codex thread each Codeman-spawned pane is writing, keyed by Codeman
|
|
69
|
+
* session id.
|
|
70
|
+
*
|
|
71
|
+
* Codeman spawns every codex pane with
|
|
72
|
+
* CODEX_INTERNAL_ORIGINATOR_OVERRIDE=codeman_<sessionId>, and codex stamps that
|
|
73
|
+
* into `session_meta.originator`. That is the ONLY link between a fresh codex
|
|
74
|
+
* pane and the rollout it is writing: such a pane knows no thread id of its own,
|
|
75
|
+
* so it cannot be folded into its own Past-Sessions row from its own side.
|
|
76
|
+
*
|
|
77
|
+
* Newest wins. `/new` typed inside the codex TUI leaves several rollouts sharing
|
|
78
|
+
* one originator, and the pane is on the most recent — so this expects `rows`
|
|
79
|
+
* newest-first, as `scanCodexSessionsHistory()` returns them.
|
|
80
|
+
*/
|
|
81
|
+
export declare function codexThreadBySessionId(rows: CodexHistorySession[]): Map<string, string>;
|
|
82
|
+
/** Test seam: drop the per-path identity cache. */
|
|
83
|
+
export declare function __clearCodexIdentityCache(): void;
|
|
84
|
+
//# sourceMappingURL=codex-transcript.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codex-transcript.d.ts","sourceRoot":"","sources":["../src/codex-transcript.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AAqCH,MAAM,WAAW,mBAAmB;IAClC,2EAA2E;IAC3E,SAAS,EAAE,MAAM,CAAC;IAClB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,gDAAgD;IAChD,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAwOD;;;;;;GAMG;AACH,wBAAsB,wBAAwB,IAAI,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAgC/E;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,mBAAmB,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAOvF;AAED,mDAAmD;AACnD,wBAAgB,yBAAyB,IAAI,IAAI,CAEhD"}
|