neoctl-web 0.1.13 → 0.1.15

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.
@@ -1,151 +0,0 @@
1
- import test from 'node:test';
2
- import assert from 'node:assert/strict';
3
- import fs from 'node:fs';
4
- import os from 'node:os';
5
- import path from 'node:path';
6
- import { Worker } from 'node:worker_threads';
7
- import { execFileSync } from 'node:child_process';
8
- import { renderXhsEditorPage } from './editor-page.mjs';
9
- import { XhsArtifactRegistry, createOpenXhsArtifactEditorTool, createReadXhsArtifactTool, serveXhsArtifact } from './artifacts.mjs';
10
- const payload = { title: 'title', body: 'body', interaction: '', hashtags: [], images: [{ url: '', caption: 'planned', overlay: '', note: '' }], review: '' };
11
- function fixture(t) { const storageDir = fs.mkdtempSync(path.join(os.tmpdir(), 'xhs-version-')); t.after(() => fs.rmSync(storageDir, { recursive: true, force: true })); return new XhsArtifactRegistry({ storageDir }); }
12
- test('CAS rejects missing/stale versions, independent registries read disk, failed persistence does not publish', t => {
13
- const a = fixture(t), item = a.add({ payload, sessionId: 's' });
14
- const b = new XhsArtifactRegistry({ storageDir: a.storageDir }); b.get(item.id, 's');
15
- assert.throws(() => a.update(item.id, { payload }, 's'), { code: 'version_conflict' });
16
- a.update(item.id, { payload: { ...payload, body: 'saved' } }, 's', 1);
17
- assert.equal(b.get(item.id, 's').version, 2);
18
- assert.throws(() => b.update(item.id, { payload }, 's', 1), { code: 'version_conflict', current_version: 2 });
19
- a.persist = () => { throw new Error('disk full'); };
20
- assert.throws(() => a.update(item.id, { payload }, 's', 2), /disk full/);
21
- assert.equal(a.get(item.id, 's').payload.body, 'saved');
22
- assert.equal(fs.existsSync(a.artifactFile(item.id) + '.lock'), false);
23
- assert.equal(a.get(item.id), undefined); assert.equal(a.get(item.id, 'other'), undefined);
24
- });
25
- test('parallel workers never both win same version', async t => {
26
- for (let round = 0; round < Number(process.env.XHS_CAS_ROUNDS || 1); round++) {
27
- const registry = fixture(t), item = registry.add({ payload, sessionId: 's' });
28
- const moduleUrl = new URL('./artifacts.mjs', import.meta.url).href;
29
- const run = body => new Promise((resolve, reject) => {
30
- const worker = new Worker(`const {parentPort,workerData}=require('node:worker_threads'); import(workerData.moduleUrl).then(({XhsArtifactRegistry})=>{const r=new XhsArtifactRegistry({storageDir:workerData.dir});try{const a=r.update(workerData.id,{payload:workerData.payload},'s',1);parentPort.postMessage({version:a.version,body:a.payload.body})}catch(e){parentPort.postMessage({code:e.code,message:e.message,syscall:e.syscall,path:e.path,stack:e.stack})}})`, { eval: true, workerData: { moduleUrl, dir: registry.storageDir, id: item.id, payload: { ...payload, body } } }); worker.on('message', resolve); worker.on('error', reject);
31
- });
32
- const results = await Promise.all([run('one'), run('two'), run('three'), run('four')]);
33
- const diagnostic = JSON.stringify({ round, results }, null, 2);
34
- assert.equal(results.filter(r => r.version === 2).length, 1, diagnostic);
35
- assert.equal(results.filter(r => ['artifact_busy', 'version_conflict'].includes(r.code)).length, 3, diagnostic);
36
- assert.equal(registry.get(item.id, 's').payload.body, results.find(r => r.version === 2).body, diagnostic);
37
- assert.equal(registry.get(item.id, 's').version, 2);
38
- }
39
- });
40
- test('model cached read binds session/agent/id/version, preserves saved edits and rejects concurrent user save/replay/restart', async t => {
41
- const registry = fixture(t), context = { session: { sessionId: 's' } };
42
- const open = createOpenXhsArtifactEditorTool({ registry }), read = createReadXhsArtifactTool({ registry });
43
- const item = registry.add({ payload, sessionId: 's' });
44
- await assert.rejects(() => open.execute(open.validate({ artifact_id: item.id, payload }), context), { code: 'read_required' });
45
- registry.update(item.id, { payload: { ...payload, body: 'user edit' } }, 's', 1);
46
- let latest = (await read.execute({ id: item.id }, context)).output;
47
- const input = open.validate({ artifact_id: item.id, payload: { ...latest.artifact.payload, review: 'model review' } });
48
- await assert.rejects(() => open.execute(input, { session: { sessionId: 'other' } }), { code: 'read_required' });
49
- await assert.rejects(() => open.execute(input, { ...context, agentId: 'other-agent' }), { code: 'read_required' });
50
- const other = registry.add({ payload, sessionId: 's' });
51
- await assert.rejects(() => open.execute(open.validate({ artifact_id: other.id, payload }), context), { code: 'read_required' });
52
- const updated = await open.execute(input, context); assert.equal(updated.output.artifact.payload.body, 'user edit');
53
- await assert.rejects(() => open.execute(input, context), { code: 'read_required' });
54
- latest = (await read.execute({ id: item.id }, context)).output;
55
- registry.update(item.id, { payload: { ...payload, body: 'new user edit' } }, 's', 3);
56
- await assert.rejects(() => open.execute(open.validate({ artifact_id: item.id, payload }), context), { code: 'version_conflict' });
57
- assert.equal(registry.get(item.id, 's').payload.body, 'new user edit');
58
- await read.execute({ id: item.id }, context);
59
- registry.readVersions.get(registry.readKey(item.id, context)).expires = 0;
60
- await assert.rejects(() => open.execute(input, context), { code: 'read_required' });
61
- const restarted = new XhsArtifactRegistry({ storageDir: registry.storageDir });
62
- assert.throws(() => restarted.updateFromRead(item.id, { payload }, context), { code: 'read_required' });
63
- });
64
- test('legacy version defaults to 1; HTTP conflict is explicit and isolated', async t => {
65
- const registry = fixture(t), item = registry.add({ payload, sessionId: 's' });
66
- const legacy = { ...item }; delete legacy.version; fs.writeFileSync(registry.artifactFile(item.id), JSON.stringify(legacy));
67
- assert.equal(registry.get(item.id, 's').version, 1);
68
- let status, body; const res = { writeHead(s) { status = s; }, end(text) { body = JSON.parse(text); } };
69
- await serveXhsArtifact(registry, { method: 'PUT' }, res, item.id, async () => ({ title: payload.title, payload, expected_version: 0 }), 's');
70
- assert.equal(status, 409); assert.equal(body.code, 'version_conflict'); assert.equal(body.current_version, 1);
71
- await serveXhsArtifact(registry, { method: 'GET' }, res, item.id, null, 'other'); assert.equal(status, 404);
72
- fs.writeFileSync(registry.artifactFile(item.id) + '.lock', 'crashed owner');
73
- await serveXhsArtifact(registry, { method: 'PUT' }, res, item.id, async () => ({ title: payload.title, payload, expected_version: 1 }), 's');
74
- assert.equal(status, 423); assert.equal(body.code, 'artifact_busy');
75
- fs.unlinkSync(registry.artifactFile(item.id) + '.lock');
76
- registry.update(item.id, { payload }, 's', 1); assert.equal(registry.get(item.id, 's').version, 2);
77
- });
78
-
79
- test('editor existing CSS is byte-equivalent to baseline', () => {
80
- const baseline = execFileSync('git', ['show', 'HEAD:web/plugins/xhs-artifact/editor-page.mjs'], { encoding: 'utf8' });
81
- const current = renderXhsEditorPage({ id: 'style', payload }, '/api/xhs-artifacts/style');
82
- assert.equal(current.match(/<style>([\s\S]*?)<\/style>/)[1], baseline.match(/<style>([\s\S]*?)<\/style>/)[1]);
83
- });
84
-
85
- test('Windows replacement retries hold CAS lock; exhausted writes are 500 and preserve old JSON', async t => {
86
- const registry = fixture(t), item = registry.add({ payload, sessionId: 's' });
87
- const second = new XhsArtifactRegistry({ storageDir: registry.storageDir });
88
- const originalRename = fs.renameSync;
89
- let calls = 0;
90
- try {
91
- fs.renameSync = (from, to) => {
92
- calls++;
93
- assert.equal(registry.get(item.id, 's').version, 1);
94
- assert.throws(() => second.update(item.id, { payload }, 's', 1), { code: 'artifact_busy' });
95
- if (calls < 3) throw Object.assign(new Error('injected Windows sharing denial'), { code: 'EPERM' });
96
- return originalRename(from, to);
97
- };
98
- if (process.platform === 'win32') {
99
- registry.update(item.id, { payload: { ...payload, body: 'committed' } }, 's', 1);
100
- assert.equal(calls, 3);
101
- assert.equal(registry.get(item.id, 's').payload.body, 'committed');
102
- }
103
- } finally { fs.renameSync = originalRename; }
104
- const before = registry.get(item.id, 's');
105
- let status, response;
106
- const res = { writeHead(value) { status = value; }, end(value) { response = JSON.parse(value); } };
107
- for (const code of ['EPERM', 'ENOSPC']) {
108
- calls = 0;
109
- try {
110
- fs.renameSync = () => { calls++; throw Object.assign(new Error('injected persistent failure'), { code }); };
111
- await serveXhsArtifact(registry, { method: 'PUT' }, res, item.id, async () => ({ title: payload.title, payload, expected_version: before.version }), 's');
112
- } finally { fs.renameSync = originalRename; }
113
- assert.equal(status, 500);
114
- assert.equal(response.code, 'artifact_write_failed');
115
- assert.equal(response.storage_code, code);
116
- assert.equal(calls, process.platform === 'win32' && code === 'EPERM' ? 21 : 1);
117
- assert.deepEqual(registry.get(item.id, 's'), before);
118
- assert.deepEqual(fs.readdirSync(registry.storageDir), [item.id + '.json']);
119
- }
120
- registry.update(item.id, { payload }, 's', before.version);
121
- assert.equal(registry.get(item.id, 's').version, before.version + 1);
122
- });
123
-
124
- test('Windows lock open retries remain exclusive and persistent lock denial is not a conflict', async t => {
125
- const registry = fixture(t), item = registry.add({ payload, sessionId: 's' });
126
- const originalOpen = fs.openSync;
127
- let calls = 0;
128
- try {
129
- fs.openSync = (name, flags, ...args) => {
130
- if (flags === 'wx' && String(name).endsWith('.lock') && ++calls < 3) throw Object.assign(new Error('delete-pending lock'), { code: 'EPERM' });
131
- return originalOpen(name, flags, ...args);
132
- };
133
- if (process.platform === 'win32') {
134
- registry.update(item.id, { payload }, 's', 1);
135
- assert.equal(calls, 3);
136
- }
137
- } finally { fs.openSync = originalOpen; }
138
- const before = registry.get(item.id, 's');
139
- let status, response;
140
- const res = { writeHead(value) { status = value; }, end(value) { response = JSON.parse(value); } };
141
- try {
142
- fs.openSync = (name, flags, ...args) => {
143
- if (flags === 'wx' && String(name).endsWith('.lock')) throw Object.assign(new Error('persistent permission denial'), { code: 'EACCES' });
144
- return originalOpen(name, flags, ...args);
145
- };
146
- await serveXhsArtifact(registry, { method: 'PUT' }, res, item.id, async () => ({ title: payload.title, payload, expected_version: before.version }), 's');
147
- } finally { fs.openSync = originalOpen; }
148
- assert.equal(status, 500); assert.equal(response.code, 'artifact_write_failed'); assert.equal(response.storage_code, 'EACCES');
149
- assert.deepEqual(registry.get(item.id, 's'), before);
150
- assert.deepEqual(fs.readdirSync(registry.storageDir), [item.id + '.json']);
151
- });