@namzu/sdk 14.0.2 → 14.0.3
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 +25 -0
- package/dist/manager/project/__tests__/a-closed-workspace-takes-no-work.test.js +40 -0
- package/dist/manager/project/__tests__/a-closed-workspace-takes-no-work.test.js.map +1 -1
- package/dist/manager/project/lifecycle.d.ts.map +1 -1
- package/dist/manager/project/lifecycle.js +17 -1
- package/dist/manager/project/lifecycle.js.map +1 -1
- package/package.json +1 -1
- package/src/manager/project/__tests__/a-closed-workspace-takes-no-work.test.ts +46 -0
- package/src/manager/project/lifecycle.ts +19 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,30 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 14.0.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- c50f9bf: `ProjectManager.archive` refuses when it cannot establish the precondition.
|
|
8
|
+
|
|
9
|
+
14.0.0 shipped archival that "refuses rather than cascading" — a workspace with
|
|
10
|
+
a live session throws `ProjectNotEmptyError` instead of closing over running
|
|
11
|
+
work. The check read the session list as
|
|
12
|
+
`(await store.listSessionsByProject?.(...)) ?? []`, and `listSessionsByProject`
|
|
13
|
+
is optional. So on a store that does not implement it, "this store cannot tell
|
|
14
|
+
me what is running here" became "nothing is running here": the workspace closed
|
|
15
|
+
over live sessions and the call returned success.
|
|
16
|
+
|
|
17
|
+
It now throws, naming the missing method and what to do instead. Both stores in
|
|
18
|
+
this package implement it, so nothing in-tree changes; a host with its own
|
|
19
|
+
`SessionStore` gets a refusal where it previously got a wrong answer.
|
|
20
|
+
|
|
21
|
+
The mistake is worth naming, because the two halves are each correct and only
|
|
22
|
+
the combination is not. Optional-on-the-interface protects implementors: a
|
|
23
|
+
host's own store should not stop compiling because the SDK grew a method. It
|
|
24
|
+
cannot also mean a **safety precondition silently passes**. Where a store
|
|
25
|
+
cannot answer the question the check exists to ask, the answer is a refusal,
|
|
26
|
+
not a default.
|
|
27
|
+
|
|
3
28
|
## 14.0.2
|
|
4
29
|
|
|
5
30
|
### Patch Changes
|
|
@@ -205,4 +205,44 @@ describe('a workspace stored before it had a status', () => {
|
|
|
205
205
|
expect(archived.status).toBe('archived');
|
|
206
206
|
});
|
|
207
207
|
});
|
|
208
|
+
describe('a store that cannot answer the precondition', () => {
|
|
209
|
+
/**
|
|
210
|
+
* `listSessionsByProject` is optional on `SessionStore` so a host's own
|
|
211
|
+
* store keeps compiling. The archive path read it as
|
|
212
|
+
* `(await store.listSessionsByProject?.(...)) ?? []`, which turned "this
|
|
213
|
+
* store cannot tell me what is running here" into "nothing is running
|
|
214
|
+
* here" — so a host with such a store closed a workspace over live
|
|
215
|
+
* sessions and got a success back. The refusal that the whole feature is
|
|
216
|
+
* about was skippable by not implementing one method.
|
|
217
|
+
*/
|
|
218
|
+
function storeWithoutTheListing(inner) {
|
|
219
|
+
const partial = {};
|
|
220
|
+
for (const key of [
|
|
221
|
+
'getProject',
|
|
222
|
+
'createProject',
|
|
223
|
+
'createSession',
|
|
224
|
+
'getSession',
|
|
225
|
+
'updateSession',
|
|
226
|
+
'setProjectStatus',
|
|
227
|
+
]) {
|
|
228
|
+
const fn = inner[key];
|
|
229
|
+
if (typeof fn === 'function')
|
|
230
|
+
partial[key] = fn.bind(inner);
|
|
231
|
+
}
|
|
232
|
+
return partial;
|
|
233
|
+
}
|
|
234
|
+
it('refuses to archive rather than assuming the workspace is empty', async () => {
|
|
235
|
+
const h = await harness();
|
|
236
|
+
await h.store.updateSession({ ...h.parentSession, status: 'active' }, TENANT);
|
|
237
|
+
const blind = new ProjectManager({ store: storeWithoutTheListing(h.store) });
|
|
238
|
+
await expect(blind.archive(h.project.id, TENANT)).rejects.toThrow(/listSessionsByProject/);
|
|
239
|
+
});
|
|
240
|
+
it('leaves the workspace open after refusing', async () => {
|
|
241
|
+
// The refusal has to happen before the write, or it is only a message.
|
|
242
|
+
const h = await harness();
|
|
243
|
+
const blind = new ProjectManager({ store: storeWithoutTheListing(h.store) });
|
|
244
|
+
await blind.archive(h.project.id, TENANT).catch(() => undefined);
|
|
245
|
+
expect((await h.store.getProject(h.project.id, TENANT))?.status).toBe('open');
|
|
246
|
+
});
|
|
247
|
+
});
|
|
208
248
|
//# sourceMappingURL=a-closed-workspace-takes-no-work.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"a-closed-workspace-takes-no-work.test.js","sourceRoot":"","sources":["../../../../src/manager/project/__tests__/a-closed-workspace-takes-no-work.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AACnE,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAA;AAChC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AAExD,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAA;AAChE,OAAO,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAA;AACtE,OAAO,EACN,kBAAkB,EAClB,oBAAoB,EACpB,iBAAiB,GACjB,MAAM,4BAA4B,CAAA;AACnC,OAAO,EAAE,wBAAwB,EAAE,MAAM,sCAAsC,CAAA;AAC/E,OAAO,EAAE,0BAA0B,EAAE,MAAM,yCAAyC,CAAA;AACpF,OAAO,EAAE,wBAAwB,EAAE,MAAM,wCAAwC,CAAA;AACjF,OAAO,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAA;AACjE,OAAO,EAAE,oBAAoB,EAAE,MAAM,kCAAkC,CAAA;AACvE,OAAO,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAA;
|
|
1
|
+
{"version":3,"file":"a-closed-workspace-takes-no-work.test.js","sourceRoot":"","sources":["../../../../src/manager/project/__tests__/a-closed-workspace-takes-no-work.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../../../src/manager/project/lifecycle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAOH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAA;AACxD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,+BAA+B,CAAA;AAE5D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAA;AAC3D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAA;AAgBhE;;;;;;;;;;GAUG;AACH,wBAAsB,kBAAkB,CACvC,KAAK,EAAE,IAAI,CAAC,YAAY,EAAE,YAAY,CAAC,EACvC,SAAS,EAAE,SAAS,EACpB,QAAQ,EAAE,QAAQ,EAClB,EAAE,EAAE,MAAM,GACR,OAAO,CAAC,OAAO,CAAC,CASlB;AAED,MAAM,WAAW,kBAAkB;IAClC,KAAK,EAAE,YAAY,CAAA;CACnB;AAED,qBAAa,cAAc;IACd,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,kBAAkB;IAErD,sCAAsC;IACtC,WAAW,CAAC,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,SAAiB,GAAG,OAAO,CAAC,OAAO,CAAC;IAI5F;;;;;;;;;;;;;OAaG;IACG,OAAO,CAAC,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../../../src/manager/project/lifecycle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAOH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAA;AACxD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,+BAA+B,CAAA;AAE5D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAA;AAC3D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAA;AAgBhE;;;;;;;;;;GAUG;AACH,wBAAsB,kBAAkB,CACvC,KAAK,EAAE,IAAI,CAAC,YAAY,EAAE,YAAY,CAAC,EACvC,SAAS,EAAE,SAAS,EACpB,QAAQ,EAAE,QAAQ,EAClB,EAAE,EAAE,MAAM,GACR,OAAO,CAAC,OAAO,CAAC,CASlB;AAED,MAAM,WAAW,kBAAkB;IAClC,KAAK,EAAE,YAAY,CAAA;CACnB;AAED,qBAAa,cAAc;IACd,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,kBAAkB;IAErD,sCAAsC;IACtC,WAAW,CAAC,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,SAAiB,GAAG,OAAO,CAAC,OAAO,CAAC;IAI5F;;;;;;;;;;;;;OAaG;IACG,OAAO,CAAC,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;IA0CzE;;;;OAIG;IACG,MAAM,CAAC,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;YAS1D,KAAK;CAwBnB"}
|
|
@@ -79,7 +79,23 @@ export class ProjectManager {
|
|
|
79
79
|
if (!project) {
|
|
80
80
|
throw new Error(`Project ${projectId} not found for tenant ${tenantId} — archive rejected`);
|
|
81
81
|
}
|
|
82
|
-
|
|
82
|
+
// An unanswerable precondition is a refusal, not an empty answer.
|
|
83
|
+
//
|
|
84
|
+
// This read used to be `?? []`, which turned "this store cannot tell me
|
|
85
|
+
// what is running here" into "nothing is running here": a store without
|
|
86
|
+
// the optional method archived the workspace over live sessions and
|
|
87
|
+
// reported success. The whole point of the check is that archival does
|
|
88
|
+
// not cascade over running work, and the check was skippable by any
|
|
89
|
+
// store that had not implemented one optional method.
|
|
90
|
+
//
|
|
91
|
+
// Optional on the interface protects implementors — a host's own store
|
|
92
|
+
// should not stop compiling because the SDK grew a method. It cannot
|
|
93
|
+
// also mean a safety precondition silently passes.
|
|
94
|
+
const listByProject = this.deps.store.listSessionsByProject;
|
|
95
|
+
if (!listByProject) {
|
|
96
|
+
throw new Error(`Project ${projectId} cannot be archived: this SessionStore does not implement listSessionsByProject, so whether a session is still running in the workspace cannot be established. Implement it, or settle and verify the sessions through your own path before closing the workspace.`);
|
|
97
|
+
}
|
|
98
|
+
const sessions = await listByProject.call(this.deps.store, projectId, tenantId);
|
|
83
99
|
const blocking = sessions.filter((s) => ARCHIVAL_BLOCKING_STATUSES.has(s.status));
|
|
84
100
|
if (blocking.length > 0) {
|
|
85
101
|
throw new ProjectNotEmptyError({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lifecycle.js","sourceRoot":"","sources":["../../../src/manager/project/lifecycle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EACN,8BAA8B,EAC9B,kBAAkB,EAClB,oBAAoB,GACpB,MAAM,yBAAyB,CAAA;AAOhC;;;;;;GAMG;AACH,MAAM,0BAA0B,GAA+B,IAAI,GAAG,CAAC;IACtE,QAAQ;IACR,QAAQ;IACR,gBAAgB;IAChB,eAAe;CACf,CAAC,CAAA;AAEF;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACvC,KAAuC,EACvC,SAAoB,EACpB,QAAkB,EAClB,EAAU;IAEV,MAAM,OAAO,GAAG,MAAM,KAAK,CAAC,UAAU,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAA;IAC3D,IAAI,CAAC,OAAO,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,WAAW,SAAS,yBAAyB,QAAQ,MAAM,EAAE,WAAW,CAAC,CAAA;IAC1F,CAAC;IACD,IAAI,OAAO,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;QACnC,MAAM,IAAI,kBAAkB,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,CAAA;IAChD,CAAC;IACD,OAAO,OAAO,CAAA;AACf,CAAC;AAMD,MAAM,OAAO,cAAc;IACG;IAA7B,YAA6B,IAAwB;QAAxB,SAAI,GAAJ,IAAI,CAAoB;IAAG,CAAC;IAEzD,sCAAsC;IACtC,WAAW,CAAC,SAAoB,EAAE,QAAkB,EAAE,EAAE,GAAG,cAAc;QACxE,OAAO,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAA;IACpE,CAAC;IAED;;;;;;;;;;;;;OAaG;IACH,KAAK,CAAC,OAAO,CAAC,SAAoB,EAAE,QAAkB;QACrD,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAA;QACrE,IAAI,CAAC,OAAO,EAAE,CAAC;YACd,MAAM,IAAI,KAAK,CAAC,WAAW,SAAS,yBAAyB,QAAQ,qBAAqB,CAAC,CAAA;QAC5F,CAAC;QAED,
|
|
1
|
+
{"version":3,"file":"lifecycle.js","sourceRoot":"","sources":["../../../src/manager/project/lifecycle.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -22,6 +22,7 @@ import type { AgentDefinition } from '../../../types/agent/factory.js'
|
|
|
22
22
|
import type { AgentTaskContext } from '../../../types/agent/task.js'
|
|
23
23
|
import type { AgentId, TenantId } from '../../../types/ids/index.js'
|
|
24
24
|
import type { SummaryId } from '../../../types/session/ids.js'
|
|
25
|
+
import type { SessionStore } from '../../../types/session/store.js'
|
|
25
26
|
import { ZERO_COST } from '../../../utils/cost.js'
|
|
26
27
|
import { AgentManager } from '../../agent/lifecycle.js'
|
|
27
28
|
import { ThreadManager } from '../../thread/lifecycle.js'
|
|
@@ -266,3 +267,48 @@ describe('a workspace stored before it had a status', () => {
|
|
|
266
267
|
expect(archived.status).toBe('archived')
|
|
267
268
|
})
|
|
268
269
|
})
|
|
270
|
+
|
|
271
|
+
describe('a store that cannot answer the precondition', () => {
|
|
272
|
+
/**
|
|
273
|
+
* `listSessionsByProject` is optional on `SessionStore` so a host's own
|
|
274
|
+
* store keeps compiling. The archive path read it as
|
|
275
|
+
* `(await store.listSessionsByProject?.(...)) ?? []`, which turned "this
|
|
276
|
+
* store cannot tell me what is running here" into "nothing is running
|
|
277
|
+
* here" — so a host with such a store closed a workspace over live
|
|
278
|
+
* sessions and got a success back. The refusal that the whole feature is
|
|
279
|
+
* about was skippable by not implementing one method.
|
|
280
|
+
*/
|
|
281
|
+
function storeWithoutTheListing(inner: SessionStore): SessionStore {
|
|
282
|
+
const partial: Record<string, unknown> = {}
|
|
283
|
+
for (const key of [
|
|
284
|
+
'getProject',
|
|
285
|
+
'createProject',
|
|
286
|
+
'createSession',
|
|
287
|
+
'getSession',
|
|
288
|
+
'updateSession',
|
|
289
|
+
'setProjectStatus',
|
|
290
|
+
]) {
|
|
291
|
+
const fn = (inner as unknown as Record<string, unknown>)[key]
|
|
292
|
+
if (typeof fn === 'function') partial[key] = (fn as (...a: unknown[]) => unknown).bind(inner)
|
|
293
|
+
}
|
|
294
|
+
return partial as unknown as SessionStore
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
it('refuses to archive rather than assuming the workspace is empty', async () => {
|
|
298
|
+
const h = await harness()
|
|
299
|
+
await h.store.updateSession({ ...h.parentSession, status: 'active' }, TENANT)
|
|
300
|
+
const blind = new ProjectManager({ store: storeWithoutTheListing(h.store) })
|
|
301
|
+
|
|
302
|
+
await expect(blind.archive(h.project.id, TENANT)).rejects.toThrow(/listSessionsByProject/)
|
|
303
|
+
})
|
|
304
|
+
|
|
305
|
+
it('leaves the workspace open after refusing', async () => {
|
|
306
|
+
// The refusal has to happen before the write, or it is only a message.
|
|
307
|
+
const h = await harness()
|
|
308
|
+
const blind = new ProjectManager({ store: storeWithoutTheListing(h.store) })
|
|
309
|
+
|
|
310
|
+
await blind.archive(h.project.id, TENANT).catch(() => undefined)
|
|
311
|
+
|
|
312
|
+
expect((await h.store.getProject(h.project.id, TENANT))?.status).toBe('open')
|
|
313
|
+
})
|
|
314
|
+
})
|
|
@@ -101,7 +101,25 @@ export class ProjectManager {
|
|
|
101
101
|
throw new Error(`Project ${projectId} not found for tenant ${tenantId} — archive rejected`)
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
-
|
|
104
|
+
// An unanswerable precondition is a refusal, not an empty answer.
|
|
105
|
+
//
|
|
106
|
+
// This read used to be `?? []`, which turned "this store cannot tell me
|
|
107
|
+
// what is running here" into "nothing is running here": a store without
|
|
108
|
+
// the optional method archived the workspace over live sessions and
|
|
109
|
+
// reported success. The whole point of the check is that archival does
|
|
110
|
+
// not cascade over running work, and the check was skippable by any
|
|
111
|
+
// store that had not implemented one optional method.
|
|
112
|
+
//
|
|
113
|
+
// Optional on the interface protects implementors — a host's own store
|
|
114
|
+
// should not stop compiling because the SDK grew a method. It cannot
|
|
115
|
+
// also mean a safety precondition silently passes.
|
|
116
|
+
const listByProject = this.deps.store.listSessionsByProject
|
|
117
|
+
if (!listByProject) {
|
|
118
|
+
throw new Error(
|
|
119
|
+
`Project ${projectId} cannot be archived: this SessionStore does not implement listSessionsByProject, so whether a session is still running in the workspace cannot be established. Implement it, or settle and verify the sessions through your own path before closing the workspace.`,
|
|
120
|
+
)
|
|
121
|
+
}
|
|
122
|
+
const sessions = await listByProject.call(this.deps.store, projectId, tenantId)
|
|
105
123
|
const blocking = sessions.filter((s) => ARCHIVAL_BLOCKING_STATUSES.has(s.status))
|
|
106
124
|
if (blocking.length > 0) {
|
|
107
125
|
throw new ProjectNotEmptyError({
|