@theokit/sdk 4.34.2 → 4.35.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/CHANGELOG.md +8 -0
- package/dist/{agent-F77TRYGM.js → agent-H6HL5ITH.js} +5 -5
- package/dist/{agent-F77TRYGM.js.map → agent-H6HL5ITH.js.map} +1 -1
- package/dist/{agent-IJUQN6RK.cjs → agent-P77NPBF4.cjs} +6 -6
- package/dist/{agent-IJUQN6RK.cjs.map → agent-P77NPBF4.cjs.map} +1 -1
- package/dist/{chunk-P7SIIQIS.cjs → chunk-3XJ7CS2C.cjs} +7 -7
- package/dist/{chunk-P7SIIQIS.cjs.map → chunk-3XJ7CS2C.cjs.map} +1 -1
- package/dist/{chunk-RMRBHTA3.cjs → chunk-AIDNODHJ.cjs} +4 -4
- package/dist/{chunk-RMRBHTA3.cjs.map → chunk-AIDNODHJ.cjs.map} +1 -1
- package/dist/{chunk-QWP3ZQ75.js → chunk-BOTK6ZUP.js} +13 -4
- package/dist/chunk-BOTK6ZUP.js.map +1 -0
- package/dist/{chunk-JZSBSUFT.js → chunk-EKFA76N4.js} +4 -4
- package/dist/{chunk-JZSBSUFT.js.map → chunk-EKFA76N4.js.map} +1 -1
- package/dist/{chunk-MNLBNL7T.js → chunk-LEJXBUBD.js} +3 -3
- package/dist/{chunk-MNLBNL7T.js.map → chunk-LEJXBUBD.js.map} +1 -1
- package/dist/{chunk-4NU7GXH2.js → chunk-OKXUMCGM.js} +3 -3
- package/dist/{chunk-4NU7GXH2.js.map → chunk-OKXUMCGM.js.map} +1 -1
- package/dist/{chunk-BOTI6ZOX.cjs → chunk-Y66627E4.cjs} +5 -5
- package/dist/{chunk-BOTI6ZOX.cjs.map → chunk-Y66627E4.cjs.map} +1 -1
- package/dist/{chunk-AFOLLMVQ.cjs → chunk-YRXTIESB.cjs} +12 -2
- package/dist/chunk-YRXTIESB.cjs.map +1 -0
- package/dist/cron.cjs +5 -5
- package/dist/cron.js +4 -4
- package/dist/eval.cjs +4 -4
- package/dist/eval.js +3 -3
- package/dist/fs-session-store-4ALCDU3K.js +10 -0
- package/dist/{fs-session-store-Q3E5S7MC.js.map → fs-session-store-4ALCDU3K.js.map} +1 -1
- package/dist/{fs-session-store-2G4O63PO.cjs → fs-session-store-IQYE35HX.cjs} +5 -5
- package/dist/{fs-session-store-2G4O63PO.cjs.map → fs-session-store-IQYE35HX.cjs.map} +1 -1
- package/dist/index.cjs +23 -23
- package/dist/index.js +6 -6
- package/dist/persistence.cjs +7 -3
- package/dist/persistence.d.cts +1 -1
- package/dist/persistence.d.ts +1 -1
- package/dist/persistence.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-AFOLLMVQ.cjs.map +0 -1
- package/dist/chunk-QWP3ZQ75.js.map +0 -1
- package/dist/fs-session-store-Q3E5S7MC.js +0 -10
package/dist/cron.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
export { Cron } from './chunk-
|
|
2
|
-
import './chunk-
|
|
1
|
+
export { Cron } from './chunk-LEJXBUBD.js';
|
|
2
|
+
import './chunk-EKFA76N4.js';
|
|
3
3
|
import './chunk-2SFBB54R.js';
|
|
4
4
|
import './chunk-HRA3CPGG.js';
|
|
5
5
|
import './chunk-7BTE3RXJ.js';
|
|
6
6
|
import './chunk-K2BQQ445.js';
|
|
7
|
-
import './chunk-
|
|
7
|
+
import './chunk-OKXUMCGM.js';
|
|
8
8
|
import './chunk-IX2LKBCD.js';
|
|
9
9
|
import './chunk-6CLRANZA.js';
|
|
10
10
|
import './chunk-EEZ7CFMM.js';
|
|
@@ -20,7 +20,7 @@ import './chunk-UJ7IQJAG.js';
|
|
|
20
20
|
import './chunk-7AD3ZTZL.js';
|
|
21
21
|
import './chunk-V4XRLPEF.js';
|
|
22
22
|
import './chunk-5PZMMF4H.js';
|
|
23
|
-
import './chunk-
|
|
23
|
+
import './chunk-BOTK6ZUP.js';
|
|
24
24
|
import './chunk-UAYYNWYJ.js';
|
|
25
25
|
import './chunk-77FOZCOT.js';
|
|
26
26
|
import './chunk-2XLKLVVR.js';
|
package/dist/eval.cjs
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var chunkS7OEXQMI_cjs = require('./chunk-S7OEXQMI.cjs');
|
|
4
|
-
var
|
|
4
|
+
var chunk3XJ7CS2C_cjs = require('./chunk-3XJ7CS2C.cjs');
|
|
5
5
|
require('./chunk-BV2MWEMV.cjs');
|
|
6
6
|
require('./chunk-MZ5ZRORA.cjs');
|
|
7
7
|
require('./chunk-G4WI3VW2.cjs');
|
|
8
8
|
var chunkBUUUWQMB_cjs = require('./chunk-BUUUWQMB.cjs');
|
|
9
|
-
require('./chunk-
|
|
9
|
+
require('./chunk-AIDNODHJ.cjs');
|
|
10
10
|
require('./chunk-WEHUJ7ZS.cjs');
|
|
11
11
|
require('./chunk-LUSXDZPV.cjs');
|
|
12
12
|
require('./chunk-IT3PWBW4.cjs');
|
|
@@ -22,7 +22,7 @@ require('./chunk-YPEPCZHF.cjs');
|
|
|
22
22
|
require('./chunk-VJ26EKGJ.cjs');
|
|
23
23
|
require('./chunk-GIW4L6HY.cjs');
|
|
24
24
|
require('./chunk-7S7KKUO6.cjs');
|
|
25
|
-
require('./chunk-
|
|
25
|
+
require('./chunk-YRXTIESB.cjs');
|
|
26
26
|
var chunkCJVMDRQB_cjs = require('./chunk-CJVMDRQB.cjs');
|
|
27
27
|
require('./chunk-JD74LN7R.cjs');
|
|
28
28
|
require('./chunk-YLQQX5W2.cjs');
|
|
@@ -768,7 +768,7 @@ function makeDefaultEmbedder(opts) {
|
|
|
768
768
|
let runtime;
|
|
769
769
|
return (texts) => {
|
|
770
770
|
if (runtime === void 0) {
|
|
771
|
-
runtime =
|
|
771
|
+
runtime = chunk3XJ7CS2C_cjs.openRouterMemoryEmbeddingProviderAdapter.create(embedderCreateOptions(opts));
|
|
772
772
|
}
|
|
773
773
|
return runtime.then((rt) => rt.embed(texts));
|
|
774
774
|
};
|
package/dist/eval.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { shellEscapePosix, LocalSandbox } from './chunk-SKWVAQAY.js';
|
|
2
|
-
import { openRouterMemoryEmbeddingProviderAdapter } from './chunk-
|
|
2
|
+
import { openRouterMemoryEmbeddingProviderAdapter } from './chunk-EKFA76N4.js';
|
|
3
3
|
import './chunk-2SFBB54R.js';
|
|
4
4
|
import './chunk-HRA3CPGG.js';
|
|
5
5
|
import './chunk-7BTE3RXJ.js';
|
|
6
6
|
import { getTracer } from './chunk-K2BQQ445.js';
|
|
7
|
-
import './chunk-
|
|
7
|
+
import './chunk-OKXUMCGM.js';
|
|
8
8
|
import './chunk-IX2LKBCD.js';
|
|
9
9
|
import './chunk-6CLRANZA.js';
|
|
10
10
|
import './chunk-EEZ7CFMM.js';
|
|
@@ -20,7 +20,7 @@ import './chunk-UJ7IQJAG.js';
|
|
|
20
20
|
import './chunk-7AD3ZTZL.js';
|
|
21
21
|
import './chunk-V4XRLPEF.js';
|
|
22
22
|
import './chunk-5PZMMF4H.js';
|
|
23
|
-
import './chunk-
|
|
23
|
+
import './chunk-BOTK6ZUP.js';
|
|
24
24
|
import { readJsonlIds, appendJsonl } from './chunk-UAYYNWYJ.js';
|
|
25
25
|
export { JsonlParseError, loadJsonl } from './chunk-UAYYNWYJ.js';
|
|
26
26
|
import './chunk-77FOZCOT.js';
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { FsSessionStore } from './chunk-OKXUMCGM.js';
|
|
2
|
+
import './chunk-BOTK6ZUP.js';
|
|
3
|
+
import './chunk-UAYYNWYJ.js';
|
|
4
|
+
import './chunk-2XLKLVVR.js';
|
|
5
|
+
import './chunk-Q56IYTBZ.js';
|
|
6
|
+
import './chunk-S2BBRVQX.js';
|
|
7
|
+
import './chunk-WLKFWQSJ.js';
|
|
8
|
+
import './chunk-JTFYYKDT.js';
|
|
9
|
+
//# sourceMappingURL=fs-session-store-4ALCDU3K.js.map
|
|
10
|
+
//# sourceMappingURL=fs-session-store-4ALCDU3K.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"fs-session-store-
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"fs-session-store-4ALCDU3K.js"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
require('./chunk-
|
|
3
|
+
var chunkAIDNODHJ_cjs = require('./chunk-AIDNODHJ.cjs');
|
|
4
|
+
require('./chunk-YRXTIESB.cjs');
|
|
5
5
|
require('./chunk-CJVMDRQB.cjs');
|
|
6
6
|
require('./chunk-YLQQX5W2.cjs');
|
|
7
7
|
require('./chunk-2DYI7MIF.cjs');
|
|
@@ -13,7 +13,7 @@ require('./chunk-BEURCLDV.cjs');
|
|
|
13
13
|
|
|
14
14
|
Object.defineProperty(exports, "FsSessionStore", {
|
|
15
15
|
enumerable: true,
|
|
16
|
-
get: function () { return
|
|
16
|
+
get: function () { return chunkAIDNODHJ_cjs.FsSessionStore; }
|
|
17
17
|
});
|
|
18
|
-
//# sourceMappingURL=fs-session-store-
|
|
19
|
-
//# sourceMappingURL=fs-session-store-
|
|
18
|
+
//# sourceMappingURL=fs-session-store-IQYE35HX.cjs.map
|
|
19
|
+
//# sourceMappingURL=fs-session-store-IQYE35HX.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"fs-session-store-
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"fs-session-store-IQYE35HX.cjs"}
|
package/dist/index.cjs
CHANGED
|
@@ -8,13 +8,13 @@ require('./chunk-EPYZOCOL.cjs');
|
|
|
8
8
|
var chunkZ2OC3UIW_cjs = require('./chunk-Z2OC3UIW.cjs');
|
|
9
9
|
require('./chunk-BWT67BI4.cjs');
|
|
10
10
|
require('./chunk-PNVDQL5Y.cjs');
|
|
11
|
-
var
|
|
12
|
-
var
|
|
11
|
+
var chunkY66627E4_cjs = require('./chunk-Y66627E4.cjs');
|
|
12
|
+
var chunk3XJ7CS2C_cjs = require('./chunk-3XJ7CS2C.cjs');
|
|
13
13
|
require('./chunk-BV2MWEMV.cjs');
|
|
14
14
|
var chunkMZ5ZRORA_cjs = require('./chunk-MZ5ZRORA.cjs');
|
|
15
15
|
require('./chunk-G4WI3VW2.cjs');
|
|
16
16
|
require('./chunk-BUUUWQMB.cjs');
|
|
17
|
-
require('./chunk-
|
|
17
|
+
require('./chunk-AIDNODHJ.cjs');
|
|
18
18
|
var chunkWEHUJ7ZS_cjs = require('./chunk-WEHUJ7ZS.cjs');
|
|
19
19
|
require('./chunk-LUSXDZPV.cjs');
|
|
20
20
|
require('./chunk-IT3PWBW4.cjs');
|
|
@@ -30,7 +30,7 @@ require('./chunk-YPEPCZHF.cjs');
|
|
|
30
30
|
require('./chunk-VJ26EKGJ.cjs');
|
|
31
31
|
require('./chunk-GIW4L6HY.cjs');
|
|
32
32
|
require('./chunk-7S7KKUO6.cjs');
|
|
33
|
-
require('./chunk-
|
|
33
|
+
require('./chunk-YRXTIESB.cjs');
|
|
34
34
|
require('./chunk-CJVMDRQB.cjs');
|
|
35
35
|
require('./chunk-JD74LN7R.cjs');
|
|
36
36
|
var chunkYLQQX5W2_cjs = require('./chunk-YLQQX5W2.cjs');
|
|
@@ -58,8 +58,8 @@ var fs = require('fs');
|
|
|
58
58
|
// src/agent-factory.ts
|
|
59
59
|
function createAgentFactory(common) {
|
|
60
60
|
return {
|
|
61
|
-
forSession: (agentId, overrides) =>
|
|
62
|
-
getOrCreate: (agentId, overrides) =>
|
|
61
|
+
forSession: (agentId, overrides) => chunk3XJ7CS2C_cjs.Agent.create(mergeAgentOptions(common, overrides, agentId)),
|
|
62
|
+
getOrCreate: (agentId, overrides) => chunk3XJ7CS2C_cjs.Agent.getOrCreate(agentId, mergeAgentOptions(common, overrides, agentId))
|
|
63
63
|
};
|
|
64
64
|
}
|
|
65
65
|
function mergeAgentOptions(common, overrides, agentId) {
|
|
@@ -1165,7 +1165,7 @@ var Memory = {
|
|
|
1165
1165
|
return await peer.IndexManager.open(openArgs);
|
|
1166
1166
|
}
|
|
1167
1167
|
const { IndexManager } = await import('./index-manager-H7HUMW52.cjs');
|
|
1168
|
-
openArgs.embedding = await resolveEmbedding(opts.embedding,
|
|
1168
|
+
openArgs.embedding = await resolveEmbedding(opts.embedding, chunk3XJ7CS2C_cjs.MEMORY_EMBEDDING_ADAPTERS);
|
|
1169
1169
|
return await IndexManager.open(openArgs);
|
|
1170
1170
|
},
|
|
1171
1171
|
/**
|
|
@@ -1176,7 +1176,7 @@ var Memory = {
|
|
|
1176
1176
|
*/
|
|
1177
1177
|
async runDreamingSweep(opts) {
|
|
1178
1178
|
const peer = await tryLoadSdkMemoryPeer();
|
|
1179
|
-
const catalog = peer !== null ? peer.MEMORY_EMBEDDING_ADAPTERS :
|
|
1179
|
+
const catalog = peer !== null ? peer.MEMORY_EMBEDDING_ADAPTERS : chunk3XJ7CS2C_cjs.MEMORY_EMBEDDING_ADAPTERS;
|
|
1180
1180
|
const sweepArgs = await buildDreamingSweepArgs(opts, catalog);
|
|
1181
1181
|
const result = peer !== null ? (
|
|
1182
1182
|
// biome-ignore lint/suspicious/noExplicitAny: peer is dynamically loaded — structural compat ensured by sdk-memory
|
|
@@ -1598,7 +1598,7 @@ function ehAgenteConstruido(m) {
|
|
|
1598
1598
|
return typeof m.send === "function";
|
|
1599
1599
|
}
|
|
1600
1600
|
async function materializar(def, indice) {
|
|
1601
|
-
const { Agent: Agent2 } = await import('./agent-
|
|
1601
|
+
const { Agent: Agent2 } = await import('./agent-P77NPBF4.cjs');
|
|
1602
1602
|
return Agent2.create({
|
|
1603
1603
|
// `AgentDefinition.model` admite o sentinel `'inherit'`, que não é um id de modelo. Herdar
|
|
1604
1604
|
// aqui significa "não declare nada e deixe o default valer" — passar o literal adiante criaria
|
|
@@ -1740,7 +1740,7 @@ var FIXTURE_USER = {
|
|
|
1740
1740
|
};
|
|
1741
1741
|
var FIXTURE_MODELS = [
|
|
1742
1742
|
{
|
|
1743
|
-
id:
|
|
1743
|
+
id: chunk3XJ7CS2C_cjs.DEFAULT_AGENTIC_MODEL_ID,
|
|
1744
1744
|
name: "Gemini 2.0 Flash",
|
|
1745
1745
|
displayName: "Gemini 2.0 Flash",
|
|
1746
1746
|
parameters: [
|
|
@@ -1948,7 +1948,7 @@ var Theokit = class {
|
|
|
1948
1948
|
envVars: p.envVars
|
|
1949
1949
|
}));
|
|
1950
1950
|
},
|
|
1951
|
-
embeddingAdapters: () => Object.entries(
|
|
1951
|
+
embeddingAdapters: () => Object.entries(chunk3XJ7CS2C_cjs.MEMORY_EMBEDDING_ADAPTERS).map(([id, adapter]) => ({
|
|
1952
1952
|
id,
|
|
1953
1953
|
transport: adapter.transport,
|
|
1954
1954
|
defaultModel: adapter.defaultModel
|
|
@@ -1980,17 +1980,17 @@ function resolveLocalProviderBaseUrl(providerName, fallback) {
|
|
|
1980
1980
|
return fallback;
|
|
1981
1981
|
}
|
|
1982
1982
|
async function executeCatalogRequest(request) {
|
|
1983
|
-
const apiKey =
|
|
1983
|
+
const apiKey = chunk3XJ7CS2C_cjs.resolveApiKey(request.apiKey);
|
|
1984
1984
|
if (apiKey === void 0) {
|
|
1985
1985
|
throw new chunkA44COQJJ_cjs.AuthenticationError("Missing API key", { code: "missing_api_key" });
|
|
1986
1986
|
}
|
|
1987
|
-
if (
|
|
1987
|
+
if (chunk3XJ7CS2C_cjs.shouldUseFixtureMode(apiKey)) {
|
|
1988
1988
|
return request.fixture;
|
|
1989
1989
|
}
|
|
1990
|
-
if (!
|
|
1990
|
+
if (!chunk3XJ7CS2C_cjs.isFixtureApiKey(apiKey) && process.env.THEOKIT_API_BASE_URL === void 0) {
|
|
1991
1991
|
throw new chunkA44COQJJ_cjs.AuthenticationError("Invalid API key", { code: "authentication_error" });
|
|
1992
1992
|
}
|
|
1993
|
-
return
|
|
1993
|
+
return chunk3XJ7CS2C_cjs.httpRequest(request.path, { apiKey });
|
|
1994
1994
|
}
|
|
1995
1995
|
|
|
1996
1996
|
// src/trajectory-helpers.ts
|
|
@@ -2106,35 +2106,35 @@ Object.defineProperty(exports, "GenerateObjectError", {
|
|
|
2106
2106
|
});
|
|
2107
2107
|
Object.defineProperty(exports, "Cron", {
|
|
2108
2108
|
enumerable: true,
|
|
2109
|
-
get: function () { return
|
|
2109
|
+
get: function () { return chunkY66627E4_cjs.Cron; }
|
|
2110
2110
|
});
|
|
2111
2111
|
Object.defineProperty(exports, "Agent", {
|
|
2112
2112
|
enumerable: true,
|
|
2113
|
-
get: function () { return
|
|
2113
|
+
get: function () { return chunk3XJ7CS2C_cjs.Agent; }
|
|
2114
2114
|
});
|
|
2115
2115
|
Object.defineProperty(exports, "AgentBuilder", {
|
|
2116
2116
|
enumerable: true,
|
|
2117
|
-
get: function () { return
|
|
2117
|
+
get: function () { return chunk3XJ7CS2C_cjs.AgentBuilder; }
|
|
2118
2118
|
});
|
|
2119
2119
|
Object.defineProperty(exports, "Tool", {
|
|
2120
2120
|
enumerable: true,
|
|
2121
|
-
get: function () { return
|
|
2121
|
+
get: function () { return chunk3XJ7CS2C_cjs.Tool; }
|
|
2122
2122
|
});
|
|
2123
2123
|
Object.defineProperty(exports, "ToolError", {
|
|
2124
2124
|
enumerable: true,
|
|
2125
|
-
get: function () { return
|
|
2125
|
+
get: function () { return chunk3XJ7CS2C_cjs.ToolError; }
|
|
2126
2126
|
});
|
|
2127
2127
|
Object.defineProperty(exports, "UsageAccumulator", {
|
|
2128
2128
|
enumerable: true,
|
|
2129
|
-
get: function () { return
|
|
2129
|
+
get: function () { return chunk3XJ7CS2C_cjs.UsageAccumulator; }
|
|
2130
2130
|
});
|
|
2131
2131
|
Object.defineProperty(exports, "computeCost", {
|
|
2132
2132
|
enumerable: true,
|
|
2133
|
-
get: function () { return
|
|
2133
|
+
get: function () { return chunk3XJ7CS2C_cjs.computeCost; }
|
|
2134
2134
|
});
|
|
2135
2135
|
Object.defineProperty(exports, "getPricingEntry", {
|
|
2136
2136
|
enumerable: true,
|
|
2137
|
-
get: function () { return
|
|
2137
|
+
get: function () { return chunk3XJ7CS2C_cjs.getPricingEntry; }
|
|
2138
2138
|
});
|
|
2139
2139
|
Object.defineProperty(exports, "emitRunEvent", {
|
|
2140
2140
|
enumerable: true,
|
package/dist/index.js
CHANGED
|
@@ -6,15 +6,15 @@ import './chunk-GJAGKFTR.js';
|
|
|
6
6
|
import { Workflow, agentStep } from './chunk-BFWPZMG7.js';
|
|
7
7
|
import './chunk-UVNG67DG.js';
|
|
8
8
|
import './chunk-CAH3G4IS.js';
|
|
9
|
-
export { Cron } from './chunk-
|
|
10
|
-
import { MEMORY_EMBEDDING_ADAPTERS, resolveApiKey, shouldUseFixtureMode, isFixtureApiKey, httpRequest, DEFAULT_AGENTIC_MODEL_ID, Agent } from './chunk-
|
|
11
|
-
export { Agent, AgentBuilder, Tool, ToolError, UsageAccumulator, computeCost, getPricingEntry } from './chunk-
|
|
9
|
+
export { Cron } from './chunk-LEJXBUBD.js';
|
|
10
|
+
import { MEMORY_EMBEDDING_ADAPTERS, resolveApiKey, shouldUseFixtureMode, isFixtureApiKey, httpRequest, DEFAULT_AGENTIC_MODEL_ID, Agent } from './chunk-EKFA76N4.js';
|
|
11
|
+
export { Agent, AgentBuilder, Tool, ToolError, UsageAccumulator, computeCost, getPricingEntry } from './chunk-EKFA76N4.js';
|
|
12
12
|
import './chunk-2SFBB54R.js';
|
|
13
13
|
import { configure, submit, list, get, cancel, subscribe } from './chunk-HRA3CPGG.js';
|
|
14
14
|
export { emitRunEvent } from './chunk-HRA3CPGG.js';
|
|
15
15
|
import './chunk-7BTE3RXJ.js';
|
|
16
16
|
import './chunk-K2BQQ445.js';
|
|
17
|
-
import './chunk-
|
|
17
|
+
import './chunk-OKXUMCGM.js';
|
|
18
18
|
import { discoverProviderPlugins, mapOllamaTransportError, mapOllamaHttpError } from './chunk-IX2LKBCD.js';
|
|
19
19
|
import './chunk-6CLRANZA.js';
|
|
20
20
|
import './chunk-EEZ7CFMM.js';
|
|
@@ -30,7 +30,7 @@ import './chunk-UJ7IQJAG.js';
|
|
|
30
30
|
import './chunk-7AD3ZTZL.js';
|
|
31
31
|
import './chunk-V4XRLPEF.js';
|
|
32
32
|
import './chunk-5PZMMF4H.js';
|
|
33
|
-
import './chunk-
|
|
33
|
+
import './chunk-BOTK6ZUP.js';
|
|
34
34
|
import './chunk-UAYYNWYJ.js';
|
|
35
35
|
import './chunk-77FOZCOT.js';
|
|
36
36
|
import { withCwdMutex } from './chunk-2XLKLVVR.js';
|
|
@@ -1600,7 +1600,7 @@ function ehAgenteConstruido(m) {
|
|
|
1600
1600
|
return typeof m.send === "function";
|
|
1601
1601
|
}
|
|
1602
1602
|
async function materializar(def, indice) {
|
|
1603
|
-
const { Agent: Agent2 } = await import('./agent-
|
|
1603
|
+
const { Agent: Agent2 } = await import('./agent-H6HL5ITH.js');
|
|
1604
1604
|
return Agent2.create({
|
|
1605
1605
|
// `AgentDefinition.model` admite o sentinel `'inherit'`, que não é um id de modelo. Herdar
|
|
1606
1606
|
// aqui significa "não declare nada e deixe o default valer" — passar o literal adiante criaria
|
package/dist/persistence.cjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var chunkPNVDQL5Y_cjs = require('./chunk-PNVDQL5Y.cjs');
|
|
4
|
-
var
|
|
4
|
+
var chunkYRXTIESB_cjs = require('./chunk-YRXTIESB.cjs');
|
|
5
5
|
var chunkCJVMDRQB_cjs = require('./chunk-CJVMDRQB.cjs');
|
|
6
6
|
var chunkJD74LN7R_cjs = require('./chunk-JD74LN7R.cjs');
|
|
7
7
|
var chunkYLQQX5W2_cjs = require('./chunk-YLQQX5W2.cjs');
|
|
@@ -83,11 +83,15 @@ Object.defineProperty(exports, "PersistenceSchema", {
|
|
|
83
83
|
});
|
|
84
84
|
Object.defineProperty(exports, "SessionBusyError", {
|
|
85
85
|
enumerable: true,
|
|
86
|
-
get: function () { return
|
|
86
|
+
get: function () { return chunkYRXTIESB_cjs.SessionBusyError; }
|
|
87
87
|
});
|
|
88
88
|
Object.defineProperty(exports, "acquireSessionWriter", {
|
|
89
89
|
enumerable: true,
|
|
90
|
-
get: function () { return
|
|
90
|
+
get: function () { return chunkYRXTIESB_cjs.acquireSessionWriter; }
|
|
91
|
+
});
|
|
92
|
+
Object.defineProperty(exports, "sessaoTemEscritor", {
|
|
93
|
+
enumerable: true,
|
|
94
|
+
get: function () { return chunkYRXTIESB_cjs.sessaoTemEscritor; }
|
|
91
95
|
});
|
|
92
96
|
Object.defineProperty(exports, "JsonlParseError", {
|
|
93
97
|
enumerable: true,
|
package/dist/persistence.d.cts
CHANGED
|
@@ -22,7 +22,7 @@ export { sanitizeFts5Query } from "./internal/persistence/fts5-sanitize.js";
|
|
|
22
22
|
export { appendJsonl, JsonlParseError, loadJsonl, readJsonlIds, } from "./internal/persistence/jsonl.js";
|
|
23
23
|
export { PersistenceSchema } from "./internal/persistence/persistence-schema.js";
|
|
24
24
|
export { encodeProjectDir, transcriptPath, transcriptRoot, } from "./internal/persistence/session-transcript.js";
|
|
25
|
-
export { acquireSessionWriter, SessionBusyError, type SessionWriterLease, } from "./internal/persistence/session-writer.js";
|
|
25
|
+
export { acquireSessionWriter, SessionBusyError, type SessionWriterLease, sessaoTemEscritor, } from "./internal/persistence/session-writer.js";
|
|
26
26
|
export type { OpenSqliteResilientOptions, ResilientSqliteDb, } from "./internal/persistence/sqlite-open.js";
|
|
27
27
|
export { isCorruptionError, openSqliteResilient } from "./internal/persistence/sqlite-open.js";
|
|
28
28
|
export type { WalApplyResult } from "./internal/persistence/sqlite-wal.js";
|
package/dist/persistence.d.ts
CHANGED
|
@@ -22,7 +22,7 @@ export { sanitizeFts5Query } from "./internal/persistence/fts5-sanitize.js";
|
|
|
22
22
|
export { appendJsonl, JsonlParseError, loadJsonl, readJsonlIds, } from "./internal/persistence/jsonl.js";
|
|
23
23
|
export { PersistenceSchema } from "./internal/persistence/persistence-schema.js";
|
|
24
24
|
export { encodeProjectDir, transcriptPath, transcriptRoot, } from "./internal/persistence/session-transcript.js";
|
|
25
|
-
export { acquireSessionWriter, SessionBusyError, type SessionWriterLease, } from "./internal/persistence/session-writer.js";
|
|
25
|
+
export { acquireSessionWriter, SessionBusyError, type SessionWriterLease, sessaoTemEscritor, } from "./internal/persistence/session-writer.js";
|
|
26
26
|
export type { OpenSqliteResilientOptions, ResilientSqliteDb, } from "./internal/persistence/sqlite-open.js";
|
|
27
27
|
export { isCorruptionError, openSqliteResilient } from "./internal/persistence/sqlite-open.js";
|
|
28
28
|
export type { WalApplyResult } from "./internal/persistence/sqlite-wal.js";
|
package/dist/persistence.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { PersistenceSchema } from './chunk-CAH3G4IS.js';
|
|
2
|
-
export { SessionBusyError, acquireSessionWriter } from './chunk-
|
|
2
|
+
export { SessionBusyError, acquireSessionWriter, sessaoTemEscritor } from './chunk-BOTK6ZUP.js';
|
|
3
3
|
export { JsonlParseError, appendJsonl, loadJsonl, readJsonlIds, withFileLock } from './chunk-UAYYNWYJ.js';
|
|
4
4
|
export { applyWalWithFallback, isCorruptionError, openSqliteResilient, sanitizeFts5Query } from './chunk-77FOZCOT.js';
|
|
5
5
|
export { withCwdMutex } from './chunk-2XLKLVVR.js';
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/internal/persistence/session-writer.ts"],"names":["TheokitAgentError","openSync","writeSync","fchmodSync","closeSync","readFileSync","hostname","rmSync"],"mappings":"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","file":"chunk-AFOLLMVQ.cjs","sourcesContent":["/**\n * M81 — single-writer lease for a session transcript.\n *\n * ## The problem\n *\n * Nothing stops two processes appending to the same JSONL transcript. The concrete case: `exec\n * resume --last` can write into the TUI's live session. Two interleaved appends to an append-only\n * file produce lines that are each individually valid and whose SEQUENCE is fiction — and nothing\n * reports it, because every line parses.\n *\n * ## Why an exclusive lockfile rather than `withFileLock`\n *\n * The plan's ADR D2 said to compose `withFileLock`, and that was the right instinct — do not build a\n * second lock mechanism. It turned out not to fit the SHAPE: `withFileLock(path, fn)` is\n * scope-based — it holds the lock for the duration of a callback. A session lease is **held across\n * turns**, for as long as the process owns the session, with an explicit `release()`. Wrapping the\n * whole session lifetime in a callback would invert control of the entire agent loop.\n *\n * So this uses the same underlying primitive `withFileLock` uses (an exclusive-create lockfile,\n * `wx`) with lease semantics on top. That keeps the mechanism single — the file-existence lock —\n * while giving it the lifetime the caller needs. The deviation from D2 is recorded here because the\n * plan's rationale (no second mechanism) still holds; only its shape assumption did not.\n *\n * ## Fail fast, never wait\n *\n * A second writer that WAITED would block `exec` behind a TUI session that can last hours. The typed\n * error lets the caller choose: fork to a new id, or give up with a real diagnosis.\n *\n * @internal\n */\n\nimport { closeSync, fchmodSync, openSync, readFileSync, rmSync, writeSync } from \"node:fs\";\nimport { hostname } from \"node:os\";\n\nimport { TheokitAgentError } from \"../../errors.js\";\n\n/**\n * M81 — another process already holds the writer lease for this session.\n *\n * Carries `sessionPath` because knowing WHICH session is busy is what lets the caller decide between\n * forking and waiting for the user to close the TUI (`rules/error-handling.md § 2` — context enough\n * to act on).\n */\nexport class SessionBusyError extends TheokitAgentError {\n override readonly name = \"SessionBusyError\";\n\n constructor(readonly sessionPath: string) {\n super(\n `another process is already writing this session: ${sessionPath}. ` +\n \"Fork it to a new id instead of appending — two writers interleave lines into a sequence \" +\n \"that parses but is not what either process wrote.\",\n { code: \"session_busy\", isRetryable: false },\n );\n }\n}\n\n/** A held writer lease. `release()` is idempotent. */\nexport interface SessionWriterLease {\n readonly sessionPath: string;\n release(): Promise<void>;\n}\n\n/**\n * Take the exclusive writer lease for `sessionPath`, or reject with {@link SessionBusyError}.\n *\n * The lock is a sibling `.lock` file created with `wx` — the same file-existence primitive the\n * SDK's `withFileLock` builds on. Exclusivity comes from the filesystem, so it holds across\n * processes, not just across async tasks in one process.\n */\n/**\n * Janela de obsolescência **entre máquinas** — e só entre elas.\n *\n * 30 s a partir da AQUISIÇÃO. O nome \"heartbeat\" seria mentira: o registro é gravado uma vez, na\n * tomada do lease, e **não** é renovado a cada escrita. A versão anterior deste comentário dizia\n * \"o dono toca o arquivo a cada aquisição, então um processo ativo nunca cruza a janela\" — falso\n * duas vezes, e a revisão adversarial mediu as duas.\n *\n * No **mesmo host** isso não importa: `reclamavel` decide pelo `pid`, que é exato, e a idade não\n * entra na conta. Entre hosts, importa e é um limite real: um dono remoto **vivo** perde o lease\n * depois de 30 s, porque não há como perguntar a outra máquina se o processo dela existe.\n *\n * **Resíduo declarado, não mecanizado** (a disciplina de `error-handling.md § 4`): renovar o\n * registro a cada append fecharia essa janela, ao custo de um `write` por turno num arquivo que\n * hoje é escrito uma vez por sessão. Não foi feito, e o caso multi-host não é o que motiva este\n * milestone — o enunciado é `exec` e TUI na mesma máquina.\n */\nexport const JANELA_DE_HEARTBEAT_MS = 30_000;\n\n/** Quem detém o lock. Gravado como JSON no `.writer.lock`. */\ninterface DonoDoLock {\n pid: number;\n hostname: string;\n mtime: number;\n}\n\n/**\n * Grava o dono com permissão restrita ao usuário.\n *\n * `0600` porque o lock é uma afirmação de POSSE: com o `0664` que o umask usual produz, outro\n * usuário do mesmo grupo pode sobrescrever o arquivo e forjar a posse da sessão — e a partir daí o\n * dono legítimo é quem passa a receber `SessionBusyError`. O conteúdo (`pid`, `hostname`) é de\n * baixa sensibilidade; o que a permissão protege é a **integridade** do sinal, não o sigilo dele.\n */\nfunction gravarDono(lockPath: string, dono: DonoDoLock): void {\n const fd = openSync(lockPath, \"w\", 0o600);\n try {\n writeSync(fd, JSON.stringify(dono));\n // O `mode` do `open` só vale na CRIAÇÃO. Um `.writer.lock` herdado de uma versão anterior — ou\n // deixado por um processo com umask diferente — continuaria `0664` depois de reclamado, e a\n // janela de forja que o modo fecha para locks novos seguiria aberta para os antigos.\n fchmodSync(fd, 0o600);\n } finally {\n closeSync(fd);\n }\n}\n\n/** Lê o dono do lock. `undefined` quando o arquivo sumiu ou o conteúdo é ilegível. */\nfunction lerDono(lockPath: string): DonoDoLock | undefined {\n let bruto: string;\n try {\n bruto = readFileSync(lockPath, \"utf8\");\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code;\n // `ENOENT` — sumiu entre o `EEXIST` e a leitura. Corrida benigna: o lock não existe mais.\n if (code === \"ENOENT\") return undefined;\n // `EISDIR` — o caminho do lock é um DIRETÓRIO. Nenhum processo desta biblioteca cria um; é\n // lixo de outra coisa, e nunca vai virar um lock legível. Fail-closed aqui trancaria a sessão\n // para sempre, sem recuperação — o oposto do que este milestone existe para garantir.\n if (code === \"EISDIR\") return undefined;\n // Qualquer outra falha de leitura (`EACCES` num diretório compartilhado, `EIO`) é diferente em\n // espécie: o lock **existe** e nós é que não conseguimos ler o dono. Tratar como livre faria\n // dois escritores conviverem — precisamente o que o lease existe para impedir —, e o `0600`\n // que protege o lock contra forja AMPLIA essa superfície: num diretório compartilhado, o lock\n // do outro usuário é ilegível por desenho.\n //\n // Não saber quem é o dono não é o mesmo que não haver dono. Fail-closed.\n throw new SessionBusyError(lockPath.replace(/\\.writer\\.lock$/, \"\"));\n }\n try {\n const d = JSON.parse(bruto) as Partial<DonoDoLock>;\n if (\n typeof d.pid !== \"number\" ||\n typeof d.hostname !== \"string\" ||\n typeof d.mtime !== \"number\"\n ) {\n return undefined;\n }\n return { pid: d.pid, hostname: d.hostname, mtime: d.mtime };\n } catch {\n // JSON ilegível: um lock que ninguém consegue interpretar não pode trancar a sessão para\n // sempre. Tratar como obsoleto é a escolha recuperável; o custo é o mesmo de um lock velho.\n return undefined;\n }\n}\n\n/** O processo existe? `signal 0` não envia nada — só consulta permissão/existência. */\nfunction processoVivo(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch (err) {\n // EPERM significa que ele EXISTE e é de outro usuário.\n return (err as NodeJS.ErrnoException).code === \"EPERM\";\n }\n}\n\n/**\n * O lock pode ser tomado de quem o detém?\n *\n * ADR-2 do plano: reclamar por `pid` sozinho tem falso positivo entre máquinas — o mesmo número\n * existe noutro host, apontando para um processo sem relação. Então:\n *\n * - **mesmo host:** o `pid` é autoritativo, e **só** ele. Processo morto ⇒ reclamável na hora;\n * processo vivo ⇒ nunca, por mais velho que o lock esteja.\n * - **outro host:** o `pid` não diz nada aqui. Só a janela de heartbeat vale, porque é o único\n * sinal que não mente entre máquinas.\n *\n * ## Por que a idade NÃO conta no mesmo host\n *\n * A primeira versão fazia `velho || !processoVivo(pid)`, e isso era um defeito grave: o `mtime` é\n * gravado na **aquisição** e não é tocado a cada append, então qualquer sessão que durasse mais que\n * a janela — isto é, **toda sessão real** — passava a ser roubável por outro processo. Dois\n * escritores no mesmo transcript é exatamente o que o lease existe para impedir.\n *\n * No mesmo host a pergunta \"o dono ainda existe?\" tem resposta exata, e a idade não acrescenta\n * informação nenhuma a ela — só um modo de errar. Manter a janela ali seria heurística por cima de\n * um fato.\n */\nfunction reclamavel(dono: DonoDoLock | undefined): boolean {\n if (dono === undefined) return true; // ilegível ou sumido\n if (dono.hostname !== hostname()) {\n return Date.now() - dono.mtime > JANELA_DE_HEARTBEAT_MS;\n }\n return !processoVivo(dono.pid);\n}\n\nexport async function acquireSessionWriter(sessionPath: string): Promise<SessionWriterLease> {\n // M95 — `.writer.lock`, NÃO `.lock`.\n //\n // `withFileLock(path, fn)` já usa `<path>.lock` como companheiro. Enquanto o lease não era\n // chamado de lugar nenhum (o defeito que este milestone corrige) a colisão era teórica; ligá-lo\n // ao mesmo arquivo faria o lease de vida longa bloquear toda seção crítica curta do mesmo path.\n //\n // Dois arquivos porque são duas coisas: `withFileLock` protege uma seção com início e fim; o\n // lease é POSSE, mantida através de turnos, com `release()` explícito — a distinção que o\n // docstring do M81 acima já explica.\n const lockPath = `${sessionPath}.writer.lock`;\n const meu: DonoDoLock = { pid: process.pid, hostname: hostname(), mtime: Date.now() };\n let fd: number;\n try {\n // O modo vale na CRIAÇÃO — o `w` de `gravarDono` não altera arquivo existente.\n fd = openSync(lockPath, \"wx\", 0o600);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== \"EEXIST\") throw err;\n // M95 — o lock existe. Até aqui isso bastava para recusar, e era o defeito: uma TUI morta por\n // SIGKILL trancava o usuário para fora da própria sessão PERMANENTEMENTE, sem caminho de\n // recuperação documentado. Agora o lock diz quem é o dono, e um dono morto cede o lugar.\n if (!reclamavel(lerDono(lockPath))) throw new SessionBusyError(sessionPath);\n gravarDono(lockPath, meu);\n return criarLease(sessionPath, lockPath);\n }\n closeSync(fd);\n gravarDono(lockPath, meu);\n\n return criarLease(sessionPath, lockPath);\n}\n\n/** O lease em si — `release()` idempotente. Extraído porque a aquisição tem dois caminhos de saída. */\nfunction criarLease(sessionPath: string, lockPath: string): SessionWriterLease {\n let released = false;\n return {\n sessionPath,\n release: async (): Promise<void> => {\n if (released) return;\n released = true;\n rmSync(lockPath, { force: true });\n },\n };\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/internal/persistence/session-writer.ts"],"names":[],"mappings":"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","file":"chunk-QWP3ZQ75.js","sourcesContent":["/**\n * M81 — single-writer lease for a session transcript.\n *\n * ## The problem\n *\n * Nothing stops two processes appending to the same JSONL transcript. The concrete case: `exec\n * resume --last` can write into the TUI's live session. Two interleaved appends to an append-only\n * file produce lines that are each individually valid and whose SEQUENCE is fiction — and nothing\n * reports it, because every line parses.\n *\n * ## Why an exclusive lockfile rather than `withFileLock`\n *\n * The plan's ADR D2 said to compose `withFileLock`, and that was the right instinct — do not build a\n * second lock mechanism. It turned out not to fit the SHAPE: `withFileLock(path, fn)` is\n * scope-based — it holds the lock for the duration of a callback. A session lease is **held across\n * turns**, for as long as the process owns the session, with an explicit `release()`. Wrapping the\n * whole session lifetime in a callback would invert control of the entire agent loop.\n *\n * So this uses the same underlying primitive `withFileLock` uses (an exclusive-create lockfile,\n * `wx`) with lease semantics on top. That keeps the mechanism single — the file-existence lock —\n * while giving it the lifetime the caller needs. The deviation from D2 is recorded here because the\n * plan's rationale (no second mechanism) still holds; only its shape assumption did not.\n *\n * ## Fail fast, never wait\n *\n * A second writer that WAITED would block `exec` behind a TUI session that can last hours. The typed\n * error lets the caller choose: fork to a new id, or give up with a real diagnosis.\n *\n * @internal\n */\n\nimport { closeSync, fchmodSync, openSync, readFileSync, rmSync, writeSync } from \"node:fs\";\nimport { hostname } from \"node:os\";\n\nimport { TheokitAgentError } from \"../../errors.js\";\n\n/**\n * M81 — another process already holds the writer lease for this session.\n *\n * Carries `sessionPath` because knowing WHICH session is busy is what lets the caller decide between\n * forking and waiting for the user to close the TUI (`rules/error-handling.md § 2` — context enough\n * to act on).\n */\nexport class SessionBusyError extends TheokitAgentError {\n override readonly name = \"SessionBusyError\";\n\n constructor(readonly sessionPath: string) {\n super(\n `another process is already writing this session: ${sessionPath}. ` +\n \"Fork it to a new id instead of appending — two writers interleave lines into a sequence \" +\n \"that parses but is not what either process wrote.\",\n { code: \"session_busy\", isRetryable: false },\n );\n }\n}\n\n/** A held writer lease. `release()` is idempotent. */\nexport interface SessionWriterLease {\n readonly sessionPath: string;\n release(): Promise<void>;\n}\n\n/**\n * Take the exclusive writer lease for `sessionPath`, or reject with {@link SessionBusyError}.\n *\n * The lock is a sibling `.lock` file created with `wx` — the same file-existence primitive the\n * SDK's `withFileLock` builds on. Exclusivity comes from the filesystem, so it holds across\n * processes, not just across async tasks in one process.\n */\n/**\n * Janela de obsolescência **entre máquinas** — e só entre elas.\n *\n * 30 s a partir da AQUISIÇÃO. O nome \"heartbeat\" seria mentira: o registro é gravado uma vez, na\n * tomada do lease, e **não** é renovado a cada escrita. A versão anterior deste comentário dizia\n * \"o dono toca o arquivo a cada aquisição, então um processo ativo nunca cruza a janela\" — falso\n * duas vezes, e a revisão adversarial mediu as duas.\n *\n * No **mesmo host** isso não importa: `reclamavel` decide pelo `pid`, que é exato, e a idade não\n * entra na conta. Entre hosts, importa e é um limite real: um dono remoto **vivo** perde o lease\n * depois de 30 s, porque não há como perguntar a outra máquina se o processo dela existe.\n *\n * **Resíduo declarado, não mecanizado** (a disciplina de `error-handling.md § 4`): renovar o\n * registro a cada append fecharia essa janela, ao custo de um `write` por turno num arquivo que\n * hoje é escrito uma vez por sessão. Não foi feito, e o caso multi-host não é o que motiva este\n * milestone — o enunciado é `exec` e TUI na mesma máquina.\n */\nexport const JANELA_DE_HEARTBEAT_MS = 30_000;\n\n/** Quem detém o lock. Gravado como JSON no `.writer.lock`. */\ninterface DonoDoLock {\n pid: number;\n hostname: string;\n mtime: number;\n}\n\n/**\n * Grava o dono com permissão restrita ao usuário.\n *\n * `0600` porque o lock é uma afirmação de POSSE: com o `0664` que o umask usual produz, outro\n * usuário do mesmo grupo pode sobrescrever o arquivo e forjar a posse da sessão — e a partir daí o\n * dono legítimo é quem passa a receber `SessionBusyError`. O conteúdo (`pid`, `hostname`) é de\n * baixa sensibilidade; o que a permissão protege é a **integridade** do sinal, não o sigilo dele.\n */\nfunction gravarDono(lockPath: string, dono: DonoDoLock): void {\n const fd = openSync(lockPath, \"w\", 0o600);\n try {\n writeSync(fd, JSON.stringify(dono));\n // O `mode` do `open` só vale na CRIAÇÃO. Um `.writer.lock` herdado de uma versão anterior — ou\n // deixado por um processo com umask diferente — continuaria `0664` depois de reclamado, e a\n // janela de forja que o modo fecha para locks novos seguiria aberta para os antigos.\n fchmodSync(fd, 0o600);\n } finally {\n closeSync(fd);\n }\n}\n\n/** Lê o dono do lock. `undefined` quando o arquivo sumiu ou o conteúdo é ilegível. */\nfunction lerDono(lockPath: string): DonoDoLock | undefined {\n let bruto: string;\n try {\n bruto = readFileSync(lockPath, \"utf8\");\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code;\n // `ENOENT` — sumiu entre o `EEXIST` e a leitura. Corrida benigna: o lock não existe mais.\n if (code === \"ENOENT\") return undefined;\n // `EISDIR` — o caminho do lock é um DIRETÓRIO. Nenhum processo desta biblioteca cria um; é\n // lixo de outra coisa, e nunca vai virar um lock legível. Fail-closed aqui trancaria a sessão\n // para sempre, sem recuperação — o oposto do que este milestone existe para garantir.\n if (code === \"EISDIR\") return undefined;\n // Qualquer outra falha de leitura (`EACCES` num diretório compartilhado, `EIO`) é diferente em\n // espécie: o lock **existe** e nós é que não conseguimos ler o dono. Tratar como livre faria\n // dois escritores conviverem — precisamente o que o lease existe para impedir —, e o `0600`\n // que protege o lock contra forja AMPLIA essa superfície: num diretório compartilhado, o lock\n // do outro usuário é ilegível por desenho.\n //\n // Não saber quem é o dono não é o mesmo que não haver dono. Fail-closed.\n throw new SessionBusyError(lockPath.replace(/\\.writer\\.lock$/, \"\"));\n }\n try {\n const d = JSON.parse(bruto) as Partial<DonoDoLock>;\n if (\n typeof d.pid !== \"number\" ||\n typeof d.hostname !== \"string\" ||\n typeof d.mtime !== \"number\"\n ) {\n return undefined;\n }\n return { pid: d.pid, hostname: d.hostname, mtime: d.mtime };\n } catch {\n // JSON ilegível: um lock que ninguém consegue interpretar não pode trancar a sessão para\n // sempre. Tratar como obsoleto é a escolha recuperável; o custo é o mesmo de um lock velho.\n return undefined;\n }\n}\n\n/** O processo existe? `signal 0` não envia nada — só consulta permissão/existência. */\nfunction processoVivo(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch (err) {\n // EPERM significa que ele EXISTE e é de outro usuário.\n return (err as NodeJS.ErrnoException).code === \"EPERM\";\n }\n}\n\n/**\n * O lock pode ser tomado de quem o detém?\n *\n * ADR-2 do plano: reclamar por `pid` sozinho tem falso positivo entre máquinas — o mesmo número\n * existe noutro host, apontando para um processo sem relação. Então:\n *\n * - **mesmo host:** o `pid` é autoritativo, e **só** ele. Processo morto ⇒ reclamável na hora;\n * processo vivo ⇒ nunca, por mais velho que o lock esteja.\n * - **outro host:** o `pid` não diz nada aqui. Só a janela de heartbeat vale, porque é o único\n * sinal que não mente entre máquinas.\n *\n * ## Por que a idade NÃO conta no mesmo host\n *\n * A primeira versão fazia `velho || !processoVivo(pid)`, e isso era um defeito grave: o `mtime` é\n * gravado na **aquisição** e não é tocado a cada append, então qualquer sessão que durasse mais que\n * a janela — isto é, **toda sessão real** — passava a ser roubável por outro processo. Dois\n * escritores no mesmo transcript é exatamente o que o lease existe para impedir.\n *\n * No mesmo host a pergunta \"o dono ainda existe?\" tem resposta exata, e a idade não acrescenta\n * informação nenhuma a ela — só um modo de errar. Manter a janela ali seria heurística por cima de\n * um fato.\n */\nfunction reclamavel(dono: DonoDoLock | undefined): boolean {\n if (dono === undefined) return true; // ilegível ou sumido\n if (dono.hostname !== hostname()) {\n return Date.now() - dono.mtime > JANELA_DE_HEARTBEAT_MS;\n }\n return !processoVivo(dono.pid);\n}\n\nexport async function acquireSessionWriter(sessionPath: string): Promise<SessionWriterLease> {\n // M95 — `.writer.lock`, NÃO `.lock`.\n //\n // `withFileLock(path, fn)` já usa `<path>.lock` como companheiro. Enquanto o lease não era\n // chamado de lugar nenhum (o defeito que este milestone corrige) a colisão era teórica; ligá-lo\n // ao mesmo arquivo faria o lease de vida longa bloquear toda seção crítica curta do mesmo path.\n //\n // Dois arquivos porque são duas coisas: `withFileLock` protege uma seção com início e fim; o\n // lease é POSSE, mantida através de turnos, com `release()` explícito — a distinção que o\n // docstring do M81 acima já explica.\n const lockPath = `${sessionPath}.writer.lock`;\n const meu: DonoDoLock = { pid: process.pid, hostname: hostname(), mtime: Date.now() };\n let fd: number;\n try {\n // O modo vale na CRIAÇÃO — o `w` de `gravarDono` não altera arquivo existente.\n fd = openSync(lockPath, \"wx\", 0o600);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== \"EEXIST\") throw err;\n // M95 — o lock existe. Até aqui isso bastava para recusar, e era o defeito: uma TUI morta por\n // SIGKILL trancava o usuário para fora da própria sessão PERMANENTEMENTE, sem caminho de\n // recuperação documentado. Agora o lock diz quem é o dono, e um dono morto cede o lugar.\n if (!reclamavel(lerDono(lockPath))) throw new SessionBusyError(sessionPath);\n gravarDono(lockPath, meu);\n return criarLease(sessionPath, lockPath);\n }\n closeSync(fd);\n gravarDono(lockPath, meu);\n\n return criarLease(sessionPath, lockPath);\n}\n\n/** O lease em si — `release()` idempotente. Extraído porque a aquisição tem dois caminhos de saída. */\nfunction criarLease(sessionPath: string, lockPath: string): SessionWriterLease {\n let released = false;\n return {\n sessionPath,\n release: async (): Promise<void> => {\n if (released) return;\n released = true;\n rmSync(lockPath, { force: true });\n },\n };\n}\n"]}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
export { FsSessionStore } from './chunk-4NU7GXH2.js';
|
|
2
|
-
import './chunk-QWP3ZQ75.js';
|
|
3
|
-
import './chunk-UAYYNWYJ.js';
|
|
4
|
-
import './chunk-2XLKLVVR.js';
|
|
5
|
-
import './chunk-Q56IYTBZ.js';
|
|
6
|
-
import './chunk-S2BBRVQX.js';
|
|
7
|
-
import './chunk-WLKFWQSJ.js';
|
|
8
|
-
import './chunk-JTFYYKDT.js';
|
|
9
|
-
//# sourceMappingURL=fs-session-store-Q3E5S7MC.js.map
|
|
10
|
-
//# sourceMappingURL=fs-session-store-Q3E5S7MC.js.map
|