osborn 0.9.12 → 0.9.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.
package/dist/index.js
CHANGED
|
@@ -15,6 +15,8 @@ import { dirname, join } from 'node:path';
|
|
|
15
15
|
import { fileURLToPath } from 'node:url';
|
|
16
16
|
import { spawn } from 'node:child_process';
|
|
17
17
|
import { homedir, tmpdir } from 'node:os';
|
|
18
|
+
import { PassThrough } from 'node:stream';
|
|
19
|
+
import { createGunzip } from 'node:zlib';
|
|
18
20
|
// Resolve __dirname for this ESM module so we can find sibling files (e.g.
|
|
19
21
|
// meeting-output.html) relative to the compiled JS location, NOT process.cwd().
|
|
20
22
|
// In production cwd is the user's workspace; the static file lives next to dist/index.js.
|
|
@@ -376,8 +378,26 @@ function startApiServer(workingDir, port) {
|
|
|
376
378
|
const targetWorkDir = url.searchParams.get('targetWorkDir');
|
|
377
379
|
const tmpDir = mkdtempSync(join(tmpdir(), 'osborn-import-'));
|
|
378
380
|
const tarProc = spawn('tar', ['-xf', '-', '-C', tmpDir]);
|
|
379
|
-
//
|
|
380
|
-
|
|
381
|
+
// Stream-sniff the first chunk to detect gzip magic bytes (0x1f 0x8b).
|
|
382
|
+
// Then route through createGunzip() if gzip, otherwise pipe raw to tar.
|
|
383
|
+
// This avoids any reliance on Content-Type or Content-Encoding headers.
|
|
384
|
+
const passthrough = new PassThrough();
|
|
385
|
+
let sniffDone = false;
|
|
386
|
+
req.once('data', (firstChunk) => {
|
|
387
|
+
sniffDone = true;
|
|
388
|
+
const isGzip = firstChunk[0] === 0x1f && firstChunk[1] === 0x8b;
|
|
389
|
+
passthrough.write(firstChunk);
|
|
390
|
+
req.pipe(passthrough);
|
|
391
|
+
const source = isGzip ? passthrough.pipe(createGunzip()) : passthrough;
|
|
392
|
+
source.pipe(tarProc.stdin);
|
|
393
|
+
});
|
|
394
|
+
req.once('end', () => {
|
|
395
|
+
if (!sniffDone) {
|
|
396
|
+
// Empty body — just end tar stdin
|
|
397
|
+
passthrough.end();
|
|
398
|
+
tarProc.stdin.end();
|
|
399
|
+
}
|
|
400
|
+
});
|
|
381
401
|
tarProc.stdin.on('error', (err) => {
|
|
382
402
|
console.error('[import] tar stdin error', err);
|
|
383
403
|
tarProc.kill('SIGTERM');
|
|
@@ -522,22 +542,24 @@ function startApiServer(workingDir, port) {
|
|
|
522
542
|
}
|
|
523
543
|
const tmpExtractDir = mkdtempSync(join(tmpdir(), 'osborn-import-'));
|
|
524
544
|
try {
|
|
525
|
-
// Reassemble chunks into a
|
|
545
|
+
// Reassemble all chunks into a combined buffer, then sniff first 2 bytes
|
|
546
|
+
// to detect gzip magic (0x1f 0x8b). Route through createGunzip() if gzip,
|
|
547
|
+
// otherwise pass raw bytes — always using tar -xf (no -z flag).
|
|
548
|
+
const chunkBuffers = [];
|
|
549
|
+
for (const chunkFile of expectedChunks) {
|
|
550
|
+
chunkBuffers.push(readFileSync(join(uploadDir, chunkFile)));
|
|
551
|
+
}
|
|
552
|
+
const combined = Buffer.concat(chunkBuffers);
|
|
553
|
+
const isGzip = combined[0] === 0x1f && combined[1] === 0x8b;
|
|
526
554
|
const tarProc = spawn('tar', ['-xf', '-', '-C', tmpExtractDir]);
|
|
527
|
-
//
|
|
555
|
+
// Feed combined buffer through gunzip (if needed) then into tar stdin
|
|
556
|
+
const feedStream = new PassThrough();
|
|
557
|
+
const tarInput = isGzip ? feedStream.pipe(createGunzip()) : feedStream;
|
|
558
|
+
tarInput.pipe(tarProc.stdin);
|
|
559
|
+
feedStream.end(combined);
|
|
528
560
|
const streamChunks = async () => {
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
await new Promise((resolve, reject) => {
|
|
532
|
-
tarProc.stdin.write(chunkData, (err) => {
|
|
533
|
-
if (err)
|
|
534
|
-
reject(err);
|
|
535
|
-
else
|
|
536
|
-
resolve();
|
|
537
|
-
});
|
|
538
|
-
});
|
|
539
|
-
}
|
|
540
|
-
tarProc.stdin.end();
|
|
561
|
+
// feeding is already initiated above; just return a resolved promise
|
|
562
|
+
await Promise.resolve();
|
|
541
563
|
};
|
|
542
564
|
streamChunks().catch(err => {
|
|
543
565
|
console.error('[import-finalize] chunk stream error', err);
|
|
@@ -13,6 +13,8 @@ Include:
|
|
|
13
13
|
- **Test results**: What was tried, what it showed, what it ruled out
|
|
14
14
|
|
|
15
15
|
Keep this under 800 characters. This stays in the compact summary — it is NOT written to disk.
|
|
16
|
+
- **ANNOUNCE**: End HANDOFF_STATE with one line formatted as:
|
|
17
|
+
`ANNOUNCE: <natural-language sentence for Osborn to speak aloud when resuming — mention that session memory was crystallized and how many skills/decisions were updated. Keep it to one sentence, conversational tone, like a colleague mentioning it in passing.>`
|
|
16
18
|
|
|
17
19
|
---
|
|
18
20
|
|
|
@@ -10,6 +10,8 @@ Session workspace: ${workspacePath}
|
|
|
10
10
|
· You CAN write other files to the workspace (detailed findings, diffs, notes, code samples) that the user sees in a files panel
|
|
11
11
|
|
|
12
12
|
Working principle: SPEAK the thinking, WRITE the details.
|
|
13
|
+
|
|
14
|
+
COMPACT RESUME BEHAVIOR: When this conversation has been compacted, the compact summary may contain a line beginning with "ANNOUNCE:". If it does, speak that line aloud as your first response before picking up any pending task. This is NOT recapping the summary — it is delivering a brief memory-crystallization update that the user is expecting. After speaking it, continue normally.
|
|
13
15
|
</context>
|
|
14
16
|
|
|
15
17
|
<objective>
|
package/dist/prompts.js
CHANGED
|
@@ -554,6 +554,8 @@ Quick lookups (1-2 calls) you can do directly. Everything else goes to an agent.
|
|
|
554
554
|
You do NOT produce findings from training data alone. You use tools to confirm every specific fact — file names, version numbers, function signatures, configuration values, URLs. If a tool is not available to verify a claim, you say so.
|
|
555
555
|
|
|
556
556
|
IF INTERRUPTED OR RESTARTED: Check ~/.claude/projects/ subagents folder for recent sub-agent JSONL files. Read the last entries to understand what was completed. Resume from that point.
|
|
557
|
+
|
|
558
|
+
Exception: if the compact summary contains a line beginning with "ANNOUNCE:", speak that line to the user as your first response before picking up the task. This is NOT recapping the summary — it is delivering a brief memory-crystallization update that the user is expecting.
|
|
557
559
|
</role>
|
|
558
560
|
|
|
559
561
|
<write-rules>
|