@roj-ai/kompjutr-platform 0.0.0 → 0.2.11

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.
Files changed (57) hide show
  1. package/README.md +114 -1
  2. package/dist/event-store.d.ts +48 -0
  3. package/dist/event-store.d.ts.map +1 -0
  4. package/dist/event-store.js +206 -0
  5. package/dist/event-store.js.map +1 -0
  6. package/dist/fs.d.ts +19 -0
  7. package/dist/fs.d.ts.map +1 -0
  8. package/dist/fs.js +200 -0
  9. package/dist/fs.js.map +1 -0
  10. package/dist/git.d.ts +12 -0
  11. package/dist/git.d.ts.map +1 -0
  12. package/dist/git.js +70 -0
  13. package/dist/git.js.map +1 -0
  14. package/dist/index.d.ts +36 -0
  15. package/dist/index.d.ts.map +1 -0
  16. package/dist/index.js +57 -0
  17. package/dist/index.js.map +1 -0
  18. package/dist/llm-call-log.d.ts +23 -0
  19. package/dist/llm-call-log.d.ts.map +1 -0
  20. package/dist/llm-call-log.js +135 -0
  21. package/dist/llm-call-log.js.map +1 -0
  22. package/dist/llm-call-payloads.d.ts +12 -0
  23. package/dist/llm-call-payloads.d.ts.map +1 -0
  24. package/dist/llm-call-payloads.js +77 -0
  25. package/dist/llm-call-payloads.js.map +1 -0
  26. package/dist/process.d.ts +14 -0
  27. package/dist/process.d.ts.map +1 -0
  28. package/dist/process.js +25 -0
  29. package/dist/process.js.map +1 -0
  30. package/dist/session-log.d.ts +22 -0
  31. package/dist/session-log.d.ts.map +1 -0
  32. package/dist/session-log.js +65 -0
  33. package/dist/session-log.js.map +1 -0
  34. package/dist/shell.d.ts +11 -0
  35. package/dist/shell.d.ts.map +1 -0
  36. package/dist/shell.js +36 -0
  37. package/dist/shell.js.map +1 -0
  38. package/dist/testing/index.d.ts +2 -0
  39. package/dist/testing/index.d.ts.map +1 -0
  40. package/dist/testing/index.js +2 -0
  41. package/dist/testing/index.js.map +1 -0
  42. package/dist/testing/storage.d.ts +29 -0
  43. package/dist/testing/storage.d.ts.map +1 -0
  44. package/dist/testing/storage.js +132 -0
  45. package/dist/testing/storage.js.map +1 -0
  46. package/package.json +44 -4
  47. package/src/event-store.ts +250 -0
  48. package/src/fs.ts +232 -0
  49. package/src/git.ts +74 -0
  50. package/src/index.ts +83 -0
  51. package/src/llm-call-log.ts +204 -0
  52. package/src/llm-call-payloads.ts +95 -0
  53. package/src/process.ts +28 -0
  54. package/src/session-log.ts +79 -0
  55. package/src/shell.ts +49 -0
  56. package/src/testing/index.ts +1 -0
  57. package/src/testing/storage.ts +141 -0
package/dist/git.js ADDED
@@ -0,0 +1,70 @@
1
+ /**
2
+ * `GitClient` port over kompjutr's git runtime.
3
+ *
4
+ * The port names four questions `git-status` asks, and kompjutr answers each
5
+ * one directly rather than by walking a tree: status reads its index tracker,
6
+ * and `divergence` counts both sides of a fork in one call. Two of the four had
7
+ * no honest answer over the binding this replaces.
8
+ */
9
+ /**
10
+ * kompjutr's ordinary codes are already the port's alphabet. Three are not:
11
+ * a rename is an add at the new path, an unmerged path is a modification, and
12
+ * an ignored one is not a change anybody asked about.
13
+ */
14
+ function toStatusEntry(entry) {
15
+ if (entry.index === '!' || entry.worktree === '!')
16
+ return undefined;
17
+ const index = entry.index === 'R' ? 'A' : entry.index === 'U' ? 'M' : entry.index;
18
+ const worktree = entry.worktree === 'U' ? 'M' : entry.worktree;
19
+ return { path: entry.path, index, worktree };
20
+ }
21
+ export function createKompjutrGitClient(git) {
22
+ return {
23
+ async status(options) {
24
+ const entries = await git.status({ dir: options.dir });
25
+ return entries.map(toStatusEntry).filter((entry) => entry !== undefined);
26
+ },
27
+ async log(options) {
28
+ const commits = await git.log({
29
+ dir: options.dir,
30
+ ref: options.ref,
31
+ depth: options.depth,
32
+ });
33
+ return commits.map((commit) => ({
34
+ oid: commit.oid,
35
+ message: commit.message,
36
+ // Git counts seconds; every SDK timestamp is milliseconds.
37
+ committedAt: commit.committer.timestamp * 1000,
38
+ }));
39
+ },
40
+ async countAhead(options) {
41
+ if (options.missingBase === 'all' && (await git.tryRevParse({ dir: options.dir, ref: options.base })) === undefined) {
42
+ const commits = await git.log({ dir: options.dir, ref: options.ref ?? 'HEAD' });
43
+ return commits.length;
44
+ }
45
+ const result = await git.divergence({
46
+ dir: options.dir,
47
+ current: options.ref ?? 'HEAD',
48
+ upstream: options.base,
49
+ });
50
+ return result.ahead;
51
+ },
52
+ async defaultBranch(options) {
53
+ try {
54
+ const ref = await git.readRef({
55
+ dir: options.dir,
56
+ ref: 'refs/remotes/origin/HEAD',
57
+ });
58
+ if (ref.kind !== 'symbolic')
59
+ return undefined;
60
+ const prefix = 'refs/remotes/origin/';
61
+ return ref.target.startsWith(prefix) ? ref.target.slice(prefix.length) || undefined : undefined;
62
+ }
63
+ catch {
64
+ // "undefined means unknown, so the caller applies its own default."
65
+ return undefined;
66
+ }
67
+ },
68
+ };
69
+ }
70
+ //# sourceMappingURL=git.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git.js","sourceRoot":"","sources":["../src/git.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Platform adapter backed by a kompjutr workspace.
3
+ *
4
+ * Lets `@roj-ai/sdk` run against a filesystem and git runtime that are SQLite
5
+ * rows rather than files on a disk — inside a Durable Object, or anywhere else
6
+ * that can hand kompjutr a SQL storage.
7
+ */
8
+ import type { Platform, Scheduler } from '@roj-ai/sdk/platform';
9
+ import type { Workspace } from '@kompjutr/do';
10
+ import type { KompjutrLLMCallLogOptions } from './llm-call-log.js';
11
+ export interface KompjutrPlatformOptions {
12
+ /** Scratch directory, created if it is not there. Defaults to `/tmp`. */
13
+ tmpDir?: string;
14
+ /**
15
+ * Drives the agent loop's re-entry. Defaults to timers, which is correct
16
+ * while the process lives and lost when it does not. A Durable Object passes
17
+ * an alarm-backed scheduler so a wake survives its isolate.
18
+ */
19
+ scheduler?: Scheduler;
20
+ /** Retention and column ceiling for the LLM call log. */
21
+ llmCallLog?: KompjutrLLMCallLogOptions;
22
+ /** How the workspace itself is isolated. Defaults to `none`. */
23
+ shellConfinement?: 'host' | 'none';
24
+ }
25
+ export declare function createKompjutrPlatform(workspace: Workspace, options?: KompjutrPlatformOptions): Platform;
26
+ export { KompjutrEventStore } from './event-store.js';
27
+ export { createKompjutrFileSystem } from './fs.js';
28
+ export type { KompjutrFileSystemOptions } from './fs.js';
29
+ export { createKompjutrGitClient } from './git.js';
30
+ export { KompjutrLLMCallLog } from './llm-call-log.js';
31
+ export type { KompjutrLLMCallLogOptions } from './llm-call-log.js';
32
+ export { createUnsupportedProcessRunner } from './process.js';
33
+ export { KompjutrSessionLog } from './session-log.js';
34
+ export { createKompjutrShellRunner } from './shell.js';
35
+ export type { KompjutrShellRunnerOptions } from './shell.js';
36
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAA;AAE/D,OAAO,KAAK,EAAO,SAAS,EAAE,MAAM,cAAc,CAAA;AAKlD,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAA;AAKlE,MAAM,WAAW,uBAAuB;IACvC,yEAAyE;IACzE,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;;;OAIG;IACH,SAAS,CAAC,EAAE,SAAS,CAAA;IACrB,yDAAyD;IACzD,UAAU,CAAC,EAAE,yBAAyB,CAAA;IACtC,gEAAgE;IAChE,gBAAgB,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;CAClC;AAED,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,SAAS,EAAE,OAAO,GAAE,uBAA4B,GAAG,QAAQ,CA2B5G;AAWD,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AACrD,OAAO,EAAE,wBAAwB,EAAE,MAAM,SAAS,CAAA;AAClD,YAAY,EAAE,yBAAyB,EAAE,MAAM,SAAS,CAAA;AACxD,OAAO,EAAE,uBAAuB,EAAE,MAAM,UAAU,CAAA;AAClD,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AACtD,YAAY,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAA;AAClE,OAAO,EAAE,8BAA8B,EAAE,MAAM,cAAc,CAAA;AAC7D,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AACrD,OAAO,EAAE,yBAAyB,EAAE,MAAM,YAAY,CAAA;AACtD,YAAY,EAAE,0BAA0B,EAAE,MAAM,YAAY,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Platform adapter backed by a kompjutr workspace.
3
+ *
4
+ * Lets `@roj-ai/sdk` run against a filesystem and git runtime that are SQLite
5
+ * rows rather than files on a disk — inside a Durable Object, or anywhere else
6
+ * that can hand kompjutr a SQL storage.
7
+ */
8
+ import { createTimerScheduler } from '@roj-ai/sdk/platform';
9
+ import { createKompjutrFileSystem } from './fs.js';
10
+ import { createKompjutrGitClient } from './git.js';
11
+ import { KompjutrLLMCallLog } from './llm-call-log.js';
12
+ import { createUnsupportedProcessRunner } from './process.js';
13
+ import { KompjutrSessionLog } from './session-log.js';
14
+ import { createKompjutrShellRunner } from './shell.js';
15
+ export function createKompjutrPlatform(workspace, options = {}) {
16
+ const tmpDir = options.tmpDir ?? '/tmp';
17
+ // A fresh workspace holds only `/`, and the port promises tmpDir is there.
18
+ workspace.filesystem.mkdir(tmpDir, { recursive: true });
19
+ const git = workspaceGit(workspace);
20
+ return {
21
+ fs: createKompjutrFileSystem({
22
+ compat: workspace.fs,
23
+ filesystem: workspace.filesystem,
24
+ }),
25
+ process: createUnsupportedProcessRunner(),
26
+ shell: createKompjutrShellRunner({
27
+ filesystem: workspace.filesystem,
28
+ git,
29
+ confinement: options.shellConfinement,
30
+ }),
31
+ git: git && createKompjutrGitClient(git),
32
+ // Omit fsRevision: kompjutr 0.1.2 does not bump it for Git-only mutations.
33
+ // Rows, not files: both logs live in the same database as the filesystem,
34
+ // and an append there is one statement against a ranged write through it.
35
+ sessionLog: new KompjutrSessionLog(workspace.db),
36
+ llmCallLog: new KompjutrLLMCallLog(workspace.db, options.llmCallLog),
37
+ scheduler: options.scheduler ?? createTimerScheduler(),
38
+ tmpDir,
39
+ };
40
+ }
41
+ /** The getter throws unless `WorkspaceOptions.git` was set — the only signal a workspace gives. */
42
+ function workspaceGit(workspace) {
43
+ try {
44
+ return workspace.git;
45
+ }
46
+ catch {
47
+ return undefined;
48
+ }
49
+ }
50
+ export { KompjutrEventStore } from './event-store.js';
51
+ export { createKompjutrFileSystem } from './fs.js';
52
+ export { createKompjutrGitClient } from './git.js';
53
+ export { KompjutrLLMCallLog } from './llm-call-log.js';
54
+ export { createUnsupportedProcessRunner } from './process.js';
55
+ export { KompjutrSessionLog } from './session-log.js';
56
+ export { createKompjutrShellRunner } from './shell.js';
57
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAA;AAG3D,OAAO,EAAE,wBAAwB,EAAE,MAAM,SAAS,CAAA;AAClD,OAAO,EAAE,uBAAuB,EAAE,MAAM,UAAU,CAAA;AAClD,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AAEtD,OAAO,EAAE,8BAA8B,EAAE,MAAM,cAAc,CAAA;AAC7D,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AACrD,OAAO,EAAE,yBAAyB,EAAE,MAAM,YAAY,CAAA;AAiBtD,MAAM,UAAU,sBAAsB,CAAC,SAAoB,EAAE,UAAmC,EAAE;IACjG,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,MAAM,CAAA;IACvC,2EAA2E;IAC3E,SAAS,CAAC,UAAU,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAEvD,MAAM,GAAG,GAAG,YAAY,CAAC,SAAS,CAAC,CAAA;IAEnC,OAAO;QACN,EAAE,EAAE,wBAAwB,CAAC;YAC5B,MAAM,EAAE,SAAS,CAAC,EAAE;YACpB,UAAU,EAAE,SAAS,CAAC,UAAU;SAChC,CAAC;QACF,OAAO,EAAE,8BAA8B,EAAE;QACzC,KAAK,EAAE,yBAAyB,CAAC;YAChC,UAAU,EAAE,SAAS,CAAC,UAAU;YAChC,GAAG;YACH,WAAW,EAAE,OAAO,CAAC,gBAAgB;SACrC,CAAC;QACF,GAAG,EAAE,GAAG,IAAI,uBAAuB,CAAC,GAAG,CAAC;QACxC,2EAA2E;QAC3E,0EAA0E;QAC1E,0EAA0E;QAC1E,UAAU,EAAE,IAAI,kBAAkB,CAAC,SAAS,CAAC,EAAE,CAAC;QAChD,UAAU,EAAE,IAAI,kBAAkB,CAAC,SAAS,CAAC,EAAE,EAAE,OAAO,CAAC,UAAU,CAAC;QACpE,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,oBAAoB,EAAE;QACtD,MAAM;KACN,CAAA;AACF,CAAC;AAED,mGAAmG;AACnG,SAAS,YAAY,CAAC,SAAoB;IACzC,IAAI,CAAC;QACJ,OAAO,SAAS,CAAC,GAAG,CAAA;IACrB,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,SAAS,CAAA;IACjB,CAAC;AACF,CAAC;AAED,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AACrD,OAAO,EAAE,wBAAwB,EAAE,MAAM,SAAS,CAAA;AAElD,OAAO,EAAE,uBAAuB,EAAE,MAAM,UAAU,CAAA;AAClD,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AAEtD,OAAO,EAAE,8BAA8B,EAAE,MAAM,cAAc,CAAA;AAC7D,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AACrD,OAAO,EAAE,yBAAyB,EAAE,MAAM,YAAY,CAAA"}
@@ -0,0 +1,23 @@
1
+ import type { SqlDatabase } from '@kompjutr/do';
2
+ import type { LLMCallOutcome, LLMCallPage, LLMCallRow, LLMCallStore } from '@roj-ai/sdk/platform';
3
+ export interface KompjutrLLMCallLogOptions {
4
+ /** Calls retained per session. Default 200; `0` keeps every call. */
5
+ maxCallsPerSession?: number;
6
+ /** Opt-in caller request clamp in UTF-8 bytes; undefined or <= 0 disables it. Does not control storage chunk size. */
7
+ maxBlobBytes?: number;
8
+ }
9
+ export declare class KompjutrLLMCallLog implements LLMCallStore {
10
+ #private;
11
+ private readonly db;
12
+ readonly maxBlobBytes: number | undefined;
13
+ constructor(db: SqlDatabase, options?: KompjutrLLMCallLogOptions);
14
+ create(sessionId: string, row: LLMCallRow): Promise<void>;
15
+ complete(sessionId: string, callId: string, outcome: LLMCallOutcome): Promise<void>;
16
+ get(sessionId: string, callId: string): Promise<LLMCallRow | null>;
17
+ list(sessionId: string, options: {
18
+ limit: number;
19
+ offset: number;
20
+ }): Promise<LLMCallPage>;
21
+ delete(sessionId: string): Promise<number>;
22
+ }
23
+ //# sourceMappingURL=llm-call-log.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llm-call-log.d.ts","sourceRoot":"","sources":["../src/llm-call-log.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAC/C,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,UAAU,EAAiB,YAAY,EAAE,MAAM,sBAAsB,CAAA;AAOhH,MAAM,WAAW,yBAAyB;IACzC,qEAAqE;IACrE,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,sHAAsH;IACtH,YAAY,CAAC,EAAE,MAAM,CAAA;CACrB;AAwCD,qBAAa,kBAAmB,YAAW,YAAY;;IAMrD,OAAO,CAAC,QAAQ,CAAC,EAAE;IALpB,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,CAAA;gBAKvB,EAAE,EAAE,WAAW,EAChC,OAAO,GAAE,yBAA8B;IAmBlC,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAqBzD,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IA4BnF,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IAIlE,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,WAAW,CAAC;IAYzF,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CA2DhD"}
@@ -0,0 +1,135 @@
1
+ import { LLMCallPayloads, storedNumber, storedString } from './llm-call-payloads.js';
2
+ const CALLS_TABLE = 'roj_llm_call';
3
+ const PAYLOAD_FORMAT = 1;
4
+ const DEFAULT_MAX_CALLS_PER_SESSION = 200;
5
+ const COLUMNS = 'call_id, agent_id, created_at, status, model, request, completed_at, duration_ms, provider_request_id, response, metrics, error';
6
+ const READ_COLUMNS = `rowid AS call_rowid, payload_format, ${COLUMNS}`;
7
+ function toStatus(value) {
8
+ if (value === 'running' || value === 'success' || value === 'error')
9
+ return value;
10
+ throw new Error('Invalid LLM call status');
11
+ }
12
+ function optionalString(value) {
13
+ return value === null ? undefined : storedString(value);
14
+ }
15
+ function optionalNumber(value) {
16
+ return value === null ? undefined : storedNumber(value);
17
+ }
18
+ function format(value) {
19
+ if (value === 0 || value === PAYLOAD_FORMAT)
20
+ return value;
21
+ throw new Error('Unsupported LLM call payload format');
22
+ }
23
+ export class KompjutrLLMCallLog {
24
+ db;
25
+ maxBlobBytes;
26
+ #maxCallsPerSession;
27
+ #payloads;
28
+ constructor(db, options = {}) {
29
+ this.db = db;
30
+ this.#maxCallsPerSession = options.maxCallsPerSession ?? DEFAULT_MAX_CALLS_PER_SESSION;
31
+ this.maxBlobBytes = options.maxBlobBytes !== undefined && options.maxBlobBytes > 0 ? options.maxBlobBytes : undefined;
32
+ this.#payloads = this.db.transactionSync(() => {
33
+ this.db.run(`CREATE TABLE IF NOT EXISTS ${CALLS_TABLE} (
34
+ session_id TEXT NOT NULL, call_id TEXT NOT NULL, agent_id TEXT NOT NULL, created_at INTEGER NOT NULL,
35
+ status TEXT NOT NULL, model TEXT NOT NULL, request TEXT NOT NULL, completed_at INTEGER, duration_ms INTEGER,
36
+ provider_request_id TEXT, response TEXT, metrics TEXT, error TEXT, payload_format INTEGER NOT NULL DEFAULT 0
37
+ )`);
38
+ const columns = this.db.all(`PRAGMA table_info(${CALLS_TABLE})`);
39
+ if (!columns.some((column) => storedString(column.name) === 'payload_format')) {
40
+ this.db.run(`ALTER TABLE ${CALLS_TABLE} ADD COLUMN payload_format INTEGER NOT NULL DEFAULT 0`);
41
+ }
42
+ this.db.run(`CREATE UNIQUE INDEX IF NOT EXISTS ${CALLS_TABLE}_by_id ON ${CALLS_TABLE} (session_id, call_id)`);
43
+ return new LLMCallPayloads(db);
44
+ });
45
+ }
46
+ async create(sessionId, row) {
47
+ this.db.transactionSync(() => {
48
+ const record = this.db.one(`INSERT INTO ${CALLS_TABLE} (session_id, ${COLUMNS}, payload_format)
49
+ VALUES (?, ?, '', ?, ?, '', '', ?, ?, NULL, NULL, NULL, NULL, ?) RETURNING rowid AS call_rowid`, sessionId, row.callId, row.createdAt, row.status, row.completedAt ?? null, row.durationMs ?? null, PAYLOAD_FORMAT);
50
+ if (record === undefined)
51
+ throw new Error('Missing inserted LLM call');
52
+ const rowid = storedNumber(record.call_rowid);
53
+ this.#writeRequest(rowid, row);
54
+ this.#writeOutcome(rowid, row);
55
+ this.#trim(sessionId);
56
+ });
57
+ }
58
+ async complete(sessionId, callId, outcome) {
59
+ this.db.transactionSync(() => {
60
+ const record = this.db.one(`SELECT rowid AS call_rowid, payload_format FROM ${CALLS_TABLE} WHERE session_id = ? AND call_id = ?`, sessionId, callId);
61
+ if (record === undefined)
62
+ return;
63
+ const rowid = storedNumber(record.call_rowid);
64
+ if (format(record.payload_format) === 0) {
65
+ const legacy = this.#get(sessionId, callId);
66
+ if (legacy === null)
67
+ throw new Error('Missing legacy LLM call');
68
+ this.#writeRequest(rowid, legacy);
69
+ this.db.run(`UPDATE ${CALLS_TABLE} SET agent_id = '', model = '', request = '' WHERE rowid = ?`, rowid);
70
+ }
71
+ this.#writeOutcome(rowid, outcome);
72
+ this.db.run(`UPDATE ${CALLS_TABLE} SET status = ?, completed_at = ?, duration_ms = ?, payload_format = ?,
73
+ provider_request_id = NULL, response = NULL, metrics = NULL, error = NULL WHERE rowid = ?`, outcome.status, outcome.completedAt, outcome.durationMs, PAYLOAD_FORMAT, rowid);
74
+ });
75
+ }
76
+ async get(sessionId, callId) {
77
+ return this.db.transactionSync(() => this.#get(sessionId, callId));
78
+ }
79
+ async list(sessionId, options) {
80
+ return this.db.transactionSync(() => {
81
+ const records = this.db.all(`SELECT ${READ_COLUMNS} FROM ${CALLS_TABLE} WHERE session_id = ? ORDER BY call_id DESC LIMIT ? OFFSET ?`, sessionId, options.limit, options.offset);
82
+ return { calls: records.map((record) => this.#toRow(record)), total: this.#count(sessionId) };
83
+ });
84
+ }
85
+ async delete(sessionId) {
86
+ return this.db.transactionSync(() => {
87
+ const calls = this.#count(sessionId);
88
+ this.db.run(`DELETE FROM ${CALLS_TABLE} WHERE session_id = ?`, sessionId);
89
+ return calls;
90
+ });
91
+ }
92
+ #get(sessionId, callId) {
93
+ const record = this.db.one(`SELECT ${READ_COLUMNS} FROM ${CALLS_TABLE} WHERE session_id = ? AND call_id = ?`, sessionId, callId);
94
+ return record === undefined ? null : this.#toRow(record);
95
+ }
96
+ #toRow(record) {
97
+ const rowid = storedNumber(record.call_rowid);
98
+ const chunked = format(record.payload_format) === PAYLOAD_FORMAT;
99
+ return {
100
+ callId: storedString(record.call_id),
101
+ agentId: storedString(chunked ? this.#payloads.read(rowid, 'agent_id') : record.agent_id),
102
+ createdAt: storedNumber(record.created_at),
103
+ status: toStatus(record.status),
104
+ model: storedString(chunked ? this.#payloads.read(rowid, 'model') : record.model),
105
+ request: storedString(chunked ? this.#payloads.read(rowid, 'request') : record.request),
106
+ completedAt: optionalNumber(record.completed_at),
107
+ durationMs: optionalNumber(record.duration_ms),
108
+ providerRequestId: chunked ? this.#payloads.read(rowid, 'provider_request_id') : optionalString(record.provider_request_id),
109
+ response: chunked ? this.#payloads.read(rowid, 'response') : optionalString(record.response),
110
+ metrics: chunked ? this.#payloads.read(rowid, 'metrics') : optionalString(record.metrics),
111
+ error: chunked ? this.#payloads.read(rowid, 'error') : optionalString(record.error),
112
+ };
113
+ }
114
+ #writeRequest(rowid, row) {
115
+ this.#payloads.write(rowid, 'agent_id', row.agentId);
116
+ this.#payloads.write(rowid, 'model', row.model);
117
+ this.#payloads.write(rowid, 'request', row.request);
118
+ }
119
+ #writeOutcome(rowid, outcome) {
120
+ this.#payloads.write(rowid, 'provider_request_id', outcome.providerRequestId);
121
+ this.#payloads.write(rowid, 'response', outcome.response);
122
+ this.#payloads.write(rowid, 'metrics', outcome.metrics);
123
+ this.#payloads.write(rowid, 'error', outcome.error);
124
+ }
125
+ #trim(sessionId) {
126
+ if (this.#maxCallsPerSession <= 0)
127
+ return;
128
+ this.db.run(`DELETE FROM ${CALLS_TABLE} WHERE session_id = ?
129
+ AND call_id < (SELECT call_id FROM ${CALLS_TABLE} WHERE session_id = ? ORDER BY call_id DESC LIMIT 1 OFFSET ?)`, sessionId, sessionId, this.#maxCallsPerSession - 1);
130
+ }
131
+ #count(sessionId) {
132
+ return storedNumber(this.db.scalar(`SELECT COUNT(*) FROM ${CALLS_TABLE} WHERE session_id = ?`, sessionId));
133
+ }
134
+ }
135
+ //# sourceMappingURL=llm-call-log.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llm-call-log.js","sourceRoot":"","sources":["../src/llm-call-log.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { SqlDatabase } from '@kompjutr/do';
2
+ type PayloadField = 'agent_id' | 'model' | 'request' | 'provider_request_id' | 'response' | 'metrics' | 'error';
3
+ export declare function storedString(value: unknown): string;
4
+ export declare function storedNumber(value: unknown): number;
5
+ export declare class LLMCallPayloads {
6
+ private readonly db;
7
+ constructor(db: SqlDatabase);
8
+ write(rowid: number, field: PayloadField, value: string | undefined): void;
9
+ read(rowid: number, field: PayloadField): string | undefined;
10
+ }
11
+ export {};
12
+ //# sourceMappingURL=llm-call-payloads.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llm-call-payloads.d.ts","sourceRoot":"","sources":["../src/llm-call-payloads.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAM/C,KAAK,YAAY,GAAG,UAAU,GAAG,OAAO,GAAG,SAAS,GAAG,qBAAqB,GAAG,UAAU,GAAG,SAAS,GAAG,OAAO,CAAA;AAE/G,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAGnD;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAGnD;AAQD,qBAAa,eAAe;IACf,OAAO,CAAC,QAAQ,CAAC,EAAE;gBAAF,EAAE,EAAE,WAAW;IAgB5C,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI;IAwB1E,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,GAAG,MAAM,GAAG,SAAS;CA6B5D"}
@@ -0,0 +1,77 @@
1
+ const CHUNK_BYTES = 256 * 1024;
2
+ const encoder = new TextEncoder();
3
+ const decoder = new TextDecoder('utf-8', { fatal: true });
4
+ export function storedString(value) {
5
+ if (typeof value !== 'string')
6
+ throw new Error('Invalid LLM call string');
7
+ return value;
8
+ }
9
+ export function storedNumber(value) {
10
+ if (typeof value !== 'number' || !Number.isFinite(value))
11
+ throw new Error('Invalid LLM call number');
12
+ return value;
13
+ }
14
+ function storedInteger(value) {
15
+ const number = storedNumber(value);
16
+ if (!Number.isSafeInteger(number) || number < 0)
17
+ throw new Error('Invalid LLM payload integer');
18
+ return number;
19
+ }
20
+ export class LLMCallPayloads {
21
+ db;
22
+ constructor(db) {
23
+ this.db = db;
24
+ db.run(`CREATE TABLE IF NOT EXISTS roj_llm_payload (
25
+ call_rowid INTEGER NOT NULL, field TEXT NOT NULL, chunk_count INTEGER NOT NULL, byte_length INTEGER,
26
+ PRIMARY KEY (call_rowid, field)
27
+ ) WITHOUT ROWID`);
28
+ db.run(`CREATE TABLE IF NOT EXISTS roj_llm_payload_chunk (
29
+ call_rowid INTEGER NOT NULL, field TEXT NOT NULL, chunk_index INTEGER NOT NULL, data BLOB NOT NULL,
30
+ PRIMARY KEY (call_rowid, field, chunk_index)
31
+ ) WITHOUT ROWID`);
32
+ // Explicit cleanup also works when the host leaves SQLite foreign keys disabled.
33
+ db.run(`CREATE TRIGGER IF NOT EXISTS roj_llm_call_payload_delete AFTER DELETE ON roj_llm_call BEGIN
34
+ DELETE FROM roj_llm_payload_chunk WHERE call_rowid = OLD.rowid;
35
+ DELETE FROM roj_llm_payload WHERE call_rowid = OLD.rowid;
36
+ END`);
37
+ }
38
+ write(rowid, field, value) {
39
+ // JSON string encoding preserves even lone UTF-16 surrogates through UTF-8 storage.
40
+ const bytes = value === undefined ? undefined : encoder.encode(JSON.stringify(value));
41
+ const count = bytes === undefined ? 0 : Math.ceil(bytes.byteLength / CHUNK_BYTES);
42
+ this.db.run('DELETE FROM roj_llm_payload_chunk WHERE call_rowid = ? AND field = ?', rowid, field);
43
+ this.db.run('INSERT OR REPLACE INTO roj_llm_payload (call_rowid, field, chunk_count, byte_length) VALUES (?, ?, ?, ?)', rowid, field, count, bytes?.byteLength ?? null);
44
+ if (bytes === undefined)
45
+ return;
46
+ for (let index = 0; index < count; index++) {
47
+ this.db.run('INSERT INTO roj_llm_payload_chunk (call_rowid, field, chunk_index, data) VALUES (?, ?, ?, ?)', rowid, field, index, bytes.slice(index * CHUNK_BYTES, (index + 1) * CHUNK_BYTES).buffer);
48
+ }
49
+ }
50
+ read(rowid, field) {
51
+ const metadata = this.db.one('SELECT chunk_count, byte_length FROM roj_llm_payload WHERE call_rowid = ? AND field = ?', rowid, field);
52
+ if (metadata === undefined)
53
+ throw new Error(`Missing LLM payload metadata: ${field}`);
54
+ const count = storedInteger(metadata.chunk_count);
55
+ const length = metadata.byte_length === null ? null : storedInteger(metadata.byte_length);
56
+ if (count !== (length === null ? 0 : Math.ceil(length / CHUNK_BYTES)) || length === 0)
57
+ throw new Error(`Invalid LLM payload size: ${field}`);
58
+ const chunks = this.db.all('SELECT chunk_index, data FROM roj_llm_payload_chunk WHERE call_rowid = ? AND field = ? ORDER BY chunk_index', rowid, field);
59
+ if (chunks.length !== count)
60
+ throw new Error(`Missing or extra LLM payload chunks: ${field}`);
61
+ if (length === null)
62
+ return undefined;
63
+ const bytes = new Uint8Array(length);
64
+ for (const [index, chunk] of chunks.entries()) {
65
+ if (storedInteger(chunk.chunk_index) !== index)
66
+ throw new Error(`Invalid LLM payload order: ${field}`);
67
+ const data = chunk.data instanceof ArrayBuffer ? new Uint8Array(chunk.data) : chunk.data;
68
+ if (!(data instanceof Uint8Array) || data.byteLength !== Math.min(CHUNK_BYTES, length - index * CHUNK_BYTES)) {
69
+ throw new Error(`Invalid LLM payload chunk: ${field}`);
70
+ }
71
+ bytes.set(data, index * CHUNK_BYTES);
72
+ }
73
+ const value = JSON.parse(decoder.decode(bytes));
74
+ return storedString(value);
75
+ }
76
+ }
77
+ //# sourceMappingURL=llm-call-payloads.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llm-call-payloads.js","sourceRoot":"","sources":["../src/llm-call-payloads.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * `ProcessRunner` for a host with no process table.
3
+ *
4
+ * The port is required, because every host the SDK knew until now had one. A
5
+ * kompjutr workspace does not: it is a filesystem and a git runtime, and the
6
+ * command lines an agent writes are answered by `platform.shell` instead.
7
+ *
8
+ * So both methods fail, and they fail loudly rather than pretending. A caller
9
+ * that needs a real process is a caller this host cannot serve, and the plugin
10
+ * profile is what keeps those callers out — not a stub that returns nothing.
11
+ */
12
+ import type { ProcessRunner } from '@roj-ai/sdk/platform';
13
+ export declare function createUnsupportedProcessRunner(): ProcessRunner;
14
+ //# sourceMappingURL=process.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"process.d.ts","sourceRoot":"","sources":["../src/process.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAgC,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAMvF,wBAAgB,8BAA8B,IAAI,aAAa,CAS9D"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * `ProcessRunner` for a host with no process table.
3
+ *
4
+ * The port is required, because every host the SDK knew until now had one. A
5
+ * kompjutr workspace does not: it is a filesystem and a git runtime, and the
6
+ * command lines an agent writes are answered by `platform.shell` instead.
7
+ *
8
+ * So both methods fail, and they fail loudly rather than pretending. A caller
9
+ * that needs a real process is a caller this host cannot serve, and the plugin
10
+ * profile is what keeps those callers out — not a stub that returns nothing.
11
+ */
12
+ function unsupported(what) {
13
+ return Object.assign(new Error(`${what} is not available: this host has no process table`), { code: 'ENOSYS' });
14
+ }
15
+ export function createUnsupportedProcessRunner() {
16
+ return {
17
+ execFile(file) {
18
+ return Promise.reject(unsupported(`execFile(${file})`));
19
+ },
20
+ spawn(command) {
21
+ throw unsupported(`spawn(${command})`);
22
+ },
23
+ };
24
+ }
25
+ //# sourceMappingURL=process.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"process.js","sourceRoot":"","sources":["../src/process.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,SAAS,WAAW,CAAC,IAAY;IAChC,OAAO,MAAM,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,GAAG,IAAI,mDAAmD,CAAC,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAA;AAChH,CAAC;AAED,MAAM,UAAU,8BAA8B;IAC7C,OAAO;QACN,QAAQ,CAAC,IAAY;YACpB,OAAO,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,YAAY,IAAI,GAAG,CAAC,CAAC,CAAA;QACxD,CAAC;QACD,KAAK,CAAC,OAAe;YACpB,MAAM,WAAW,CAAC,SAAS,OAAO,GAAG,CAAC,CAAA;QACvC,CAAC;KACD,CAAA;AACF,CAAC"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * `session.log` as rows rather than a file in the workspace.
3
+ *
4
+ * The workspace filesystem is itself SQLite, so appending a log line means
5
+ * reading the file's length and writing a range through it, where a bound
6
+ * INSERT is one statement. The session log is the great majority of the write
7
+ * operations a turn makes, so the file shape is what a turn spends its I/O on.
8
+ *
9
+ * Clustered on `(session_id, seq)` `WITHOUT ROWID`: one session's lines are
10
+ * contiguous and a tail read is a seek down the key rather than a scan.
11
+ */
12
+ import type { SessionLogPage, SessionLogStore } from '@roj-ai/sdk/platform';
13
+ import type { SqlDatabase } from '@kompjutr/do';
14
+ export declare class KompjutrSessionLog implements SessionLogStore {
15
+ #private;
16
+ private readonly db;
17
+ constructor(db: SqlDatabase);
18
+ append(sessionId: string, line: string): void;
19
+ read(sessionId: string, since: number): Promise<SessionLogPage>;
20
+ delete(sessionId: string): Promise<number>;
21
+ }
22
+ //# sourceMappingURL=session-log.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-log.d.ts","sourceRoot":"","sources":["../src/session-log.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAC3E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAI/C,qBAAa,kBAAmB,YAAW,eAAe;;IAI7C,OAAO,CAAC,QAAQ,CAAC,EAAE;gBAAF,EAAE,EAAE,WAAW;IAW5C,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAYvC,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAe/D,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAmBhD"}
@@ -0,0 +1,65 @@
1
+ /**
2
+ * `session.log` as rows rather than a file in the workspace.
3
+ *
4
+ * The workspace filesystem is itself SQLite, so appending a log line means
5
+ * reading the file's length and writing a range through it, where a bound
6
+ * INSERT is one statement. The session log is the great majority of the write
7
+ * operations a turn makes, so the file shape is what a turn spends its I/O on.
8
+ *
9
+ * Clustered on `(session_id, seq)` `WITHOUT ROWID`: one session's lines are
10
+ * contiguous and a tail read is a seek down the key rather than a scan.
11
+ */
12
+ const LOG_TABLE = 'roj_session_log';
13
+ export class KompjutrSessionLog {
14
+ db;
15
+ /** Next seq per session, so an append does not re-derive MAX(seq) per line. */
16
+ #nextSeq = new Map();
17
+ constructor(db) {
18
+ this.db = db;
19
+ this.db.run(`CREATE TABLE IF NOT EXISTS ${LOG_TABLE} (
20
+ session_id TEXT NOT NULL,
21
+ seq INTEGER NOT NULL,
22
+ line TEXT NOT NULL,
23
+ PRIMARY KEY (session_id, seq)
24
+ ) WITHOUT ROWID`);
25
+ }
26
+ append(sessionId, line) {
27
+ try {
28
+ const seq = this.#claimSeq(sessionId);
29
+ this.db.run(`INSERT INTO ${LOG_TABLE} (session_id, seq, line) VALUES (?, ?, ?)`, sessionId, seq, line);
30
+ }
31
+ catch {
32
+ // A dropped line must never fail the caller — nothing awaits logging, and
33
+ // the file logger swallows a failed append for the same reason. The cached
34
+ // seq goes with it: if this collided, keeping it would collide forever.
35
+ this.#nextSeq.delete(sessionId);
36
+ }
37
+ }
38
+ async read(sessionId, since) {
39
+ const rows = this.db.all(`SELECT seq, line FROM ${LOG_TABLE} WHERE session_id = ? AND seq > ? ORDER BY seq`, sessionId, since);
40
+ const last = rows[rows.length - 1];
41
+ if (last !== undefined)
42
+ return { lines: rows.map((row) => row.line), offset: last.seq };
43
+ // Nothing after `since`: report the tail, so a cursor left past the end — a
44
+ // reaped session, a fresh table — rewinds instead of sticking there.
45
+ return { lines: [], offset: Math.min(since, this.#maxSeq(sessionId)) };
46
+ }
47
+ async delete(sessionId) {
48
+ const lines = this.db.scalar(`SELECT COUNT(*) FROM ${LOG_TABLE} WHERE session_id = ?`, sessionId) ?? 0;
49
+ this.db.run(`DELETE FROM ${LOG_TABLE} WHERE session_id = ?`, sessionId);
50
+ // Per-session state; a deleted session must not keep a seq to continue from.
51
+ this.#nextSeq.delete(sessionId);
52
+ return lines;
53
+ }
54
+ /** 1-based, so the default `since: 0` includes the very first line. */
55
+ #claimSeq(sessionId) {
56
+ const seq = this.#nextSeq.get(sessionId) ?? this.#maxSeq(sessionId) + 1;
57
+ this.#nextSeq.set(sessionId, seq + 1);
58
+ return seq;
59
+ }
60
+ /** Last stored seq, 0 when the session has none. */
61
+ #maxSeq(sessionId) {
62
+ return this.db.scalar(`SELECT MAX(seq) FROM ${LOG_TABLE} WHERE session_id = ?`, sessionId) ?? 0;
63
+ }
64
+ }
65
+ //# sourceMappingURL=session-log.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-log.js","sourceRoot":"","sources":["../src/session-log.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAKH,MAAM,SAAS,GAAG,iBAAiB,CAAA;AAEnC,MAAM,OAAO,kBAAkB;IAID;IAH7B,+EAA+E;IACtE,QAAQ,GAAG,IAAI,GAAG,EAAkB,CAAA;IAE7C,YAA6B,EAAe;QAAf,OAAE,GAAF,EAAE,CAAa;QAC3C,IAAI,CAAC,EAAE,CAAC,GAAG,CACV,8BAA8B,SAAS;;;;;mBAKvB,CAChB,CAAA;IACF,CAAC;IAED,MAAM,CAAC,SAAiB,EAAE,IAAY;QACrC,IAAI,CAAC;YACJ,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAA;YACrC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,eAAe,SAAS,2CAA2C,EAAE,SAAS,EAAE,GAAG,EAAE,IAAI,CAAC,CAAA;QACvG,CAAC;QAAC,MAAM,CAAC;YACR,0EAA0E;YAC1E,2EAA2E;YAC3E,wEAAwE;YACxE,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;QAChC,CAAC;IACF,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,SAAiB,EAAE,KAAa;QAC1C,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,GAAG,CACvB,yBAAyB,SAAS,gDAAgD,EAClF,SAAS,EACT,KAAK,CACL,CAAA;QAED,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;QAClC,IAAI,IAAI,KAAK,SAAS;YAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,EAAE,CAAA;QAEvF,4EAA4E;QAC5E,qEAAqE;QACrE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,EAAE,CAAA;IACvE,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,SAAiB;QAC7B,MAAM,KAAK,GAAG,IAAI,CAAC,EAAE,CAAC,MAAM,CAAS,wBAAwB,SAAS,uBAAuB,EAAE,SAAS,CAAC,IAAI,CAAC,CAAA;QAC9G,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,eAAe,SAAS,uBAAuB,EAAE,SAAS,CAAC,CAAA;QACvE,6EAA6E;QAC7E,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;QAC/B,OAAO,KAAK,CAAA;IACb,CAAC;IAED,uEAAuE;IACvE,SAAS,CAAC,SAAiB;QAC1B,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,CAAA;QACvE,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,EAAE,GAAG,GAAG,CAAC,CAAC,CAAA;QACrC,OAAO,GAAG,CAAA;IACX,CAAC;IAED,oDAAoD;IACpD,OAAO,CAAC,SAAiB;QACxB,OAAO,IAAI,CAAC,EAAE,CAAC,MAAM,CAAgB,wBAAwB,SAAS,uBAAuB,EAAE,SAAS,CAAC,IAAI,CAAC,CAAA;IAC/G,CAAC;CACD"}
@@ -0,0 +1,11 @@
1
+ import type { ShellRunner } from '@roj-ai/sdk/platform';
2
+ import type { Filesystem, Git } from '@kompjutr/do';
3
+ export interface KompjutrShellRunnerOptions {
4
+ filesystem: Filesystem;
5
+ /** Adds the `git` command when the workspace was configured with Git. */
6
+ git?: Git;
7
+ /** `host` is valid only when this workspace contains one session's files. */
8
+ confinement?: 'host' | 'none';
9
+ }
10
+ export declare function createKompjutrShellRunner(options: KompjutrShellRunnerOptions): ShellRunner;
11
+ //# sourceMappingURL=shell.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shell.d.ts","sourceRoot":"","sources":["../src/shell.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AACvD,OAAO,KAAK,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,cAAc,CAAA;AAInD,MAAM,WAAW,0BAA0B;IAC1C,UAAU,EAAE,UAAU,CAAA;IACtB,yEAAyE;IACzE,GAAG,CAAC,EAAE,GAAG,CAAA;IACT,6EAA6E;IAC7E,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;CAC7B;AAMD,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,0BAA0B,GAAG,WAAW,CA+B1F"}