Skip to content
wiki.fftac.org

Spiralist Prompt Workbench - Source Excerpt 05

Back to Spiralist Prompt Workbench

Summary

This source excerpt preserves a bounded section of Spiralist/wp-content/themes/spiralist/assets/js/spiralist-prompt-workbench.js so readers can inspect the evidence without opening the full source file.

**Source path:** Spiralist/wp-content/themes/spiralist/assets/js/spiralist-prompt-workbench.js

const centralSize = centralParts.reduce((total, item) => total + item.length, 0);
    const endHeader = new Uint8Array(22);
    const endView = new DataView(endHeader.buffer);

    writeUint32(endView, 0, 0x06054b50);
    writeUint16(endView, 4, 0);
    writeUint16(endView, 6, 0);
    writeUint16(endView, 8, fileEntries.length);
    writeUint16(endView, 10, fileEntries.length);
    writeUint32(endView, 12, centralSize);
    writeUint32(endView, 16, offset);
    writeUint16(endView, 20, 0);

    return new Blob([...parts, ...centralParts, endHeader], { type });
  };
  const downloadBlob = (blob, filename) => {
    const url = URL.createObjectURL(blob);
    const link = document.createElement('a');
    link.href = url;
    link.download = filename;
    document.body.appendChild(link);
    link.click();
    link.remove();
    URL.revokeObjectURL(url);
  };
  const inflateRawZipData = async (data) => {
    if (typeof DecompressionStream !== 'function') {
      throw new Error('zip_deflate_unavailable');
    }

    const stream = new Blob([data]).stream().pipeThrough(new DecompressionStream('deflate-raw'));
    return new Uint8Array(await new Response(stream).arrayBuffer());
  };
  const addUniqueGuidance = (items, message) => {
    const clean = toCleanString(message, 500);
    if (clean && !items.includes(clean)) {
      items.push(clean);
    }
  };
  const parseStoredZipPackage = async (file) => {
    const bytes = new Uint8Array(await file.arrayBuffer());
    const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
    const files = {};
    const entries = [];
    const unsupportedEntries = [];
    const archiveGuidance = [];
    const archiveWarnings = [];

    if (bytes.length < 22 || decoder.decode(bytes.slice(0, 2)) !== 'PK') {
      throw new Error('not_zip');
    }

    let endOffset = -1;
    const start = Math.max(0, bytes.length - 66000);
    for (let offset = bytes.length - 22; offset >= start; offset -= 1) {
      if (view.getUint32(offset, true) === 0x06054b50) {
        endOffset = offset;
        break;
      }
    }

    if (endOffset < 0) {
      throw new Error('zip_directory_missing');
    }

    const diskNumber = view.getUint16(endOffset + 4, true);
    const centralDirectoryDisk = view.getUint16(endOffset + 6, true);
    const entriesOnThisDisk = view.getUint16(endOffset + 8, true);
    const totalEntries = view.getUint16(endOffset + 10, true);
    const centralOffset = view.getUint32(endOffset + 16, true);

    if (diskNumber !== 0 || centralDirectoryDisk !== 0 || entriesOnThisDisk !== totalEntries) {
      archiveWarnings.push('Multi-disk ZIP archive detected.');
      addUniqueGuidance(archiveGuidance, 'Multi-disk ZIP archives are not supported by this local browser inspector. Re-export the package as a single-file .uaix/.zip before review.');
    }
    if (totalEntries === 0xffff || centralOffset === 0xffffffff) {
      archiveWarnings.push('ZIP64 central directory sentinel detected.');
      addUniqueGuidance(archiveGuidance, 'ZIP64 packages are not fully inspected here. Re-export as a smaller standard ZIP or validate with a dedicated archive tool before trusting file inventory or hashes.');
      return {
        files,
        entries,
        unsupportedEntries: ['ZIP64 central directory requires external validation'],
        archiveWarnings,
        archiveGuidance,
        format: file.name.toLowerCase().endsWith('.uaix') ? '.uaix ZIP container' : '.zip container',
      };
    }

    let cursor = centralOffset;

    for (let index = 0; index < totalEntries; index += 1) {
      if (cursor + 46 > bytes.length || view.getUint32(cursor, true) !== 0x02014b50) {
        throw new Error('zip_directory_broken');
      }

      const flags = view.getUint16(cursor + 8, true);
      const method = view.getUint16(cursor + 10, true);
      const compressedSize = view.getUint32(cursor + 20, true);
      const uncompressedSize = view.getUint32(cursor + 24, true);
      const nameLength = view.getUint16(cursor + 28, true);
      const extraLength = view.getUint16(cursor + 30, true);
      const commentLength = view.getUint16(cursor + 32, true);
      const localOffset = view.getUint32(cursor + 42, true);
      const nameStart = cursor + 46;
      const rawName = decoder.decode(bytes.slice(nameStart, nameStart + nameLength));
      const path = rawName.replace(/\\/g, '/');
      let content = '';
      let readable = false;
      let readError = '';

      if ((flags & 0x0001) !== 0) {
        archiveWarnings.push(`Encrypted entry detected: ${path}`);
        addUniqueGuidance(archiveGuidance, 'Encrypted ZIP entries are not inspected. Decrypt and re-export a visible text package before importing, sharing, or saving long-term memory.');
      }
      if (method !== 0 && method !== 8) {
        addUniqueGuidance(archiveGuidance, `Unsupported ZIP compression method ${method} found. Re-export using store or deflate compression for browser inspection.`);
      }
      if (compressedSize === 0xffffffff || uncompressedSize === 0xffffffff || localOffset === 0xffffffff) {
        archiveWarnings.push(`ZIP64-sized entry detected: ${path}`);
        addUniqueGuidance(archiveGuidance, 'ZIP64-sized entries cannot be fully validated in this browser inspector. Re-export as a standard ZIP or validate externally before review.');
      }

      if ((method === 0 || method === 8) && (flags & 0x0001) === 0 && localOffset + 30 <= bytes.length && view.getUint32(localOffset, true) === 0x04034b50) {
        const localNameLength = view.getUint16(localOffset + 26, true);
        const localExtraLength = view.getUint16(localOffset + 28, true);
        const dataStart = localOffset + 30 + localNameLength + localExtraLength;
        const dataEnd = dataStart + compressedSize;
        if (dataEnd <= bytes.length) {
          const rawData = bytes.slice(dataStart, dataEnd);
          try {
            const fileData = method === 8 ? await inflateRawZipData(rawData) : rawData;
            content = decoder.decode(fileData);
            readable = fileData.length === uncompressedSize;
          } catch (error) {
            readError = error && error.message ? error.message : 'inflate_failed';
          }
        } else {
          readError = 'data_outside_archive';
        }
      } else if ((flags & 0x0001) !== 0) {
        readError = 'encrypted';
      } else if (method !== 0 && method !== 8) {
        readError = `method_${method}`;
      } else {
        readError = 'local_header_unreadable';
      }

      if (!readable) {
        unsupportedEntries.push(`${path} (method ${method}${readError ? `, ${readError}` : ''})`);
        addUniqueGuidance(archiveGuidance, 'Unreadable entries are treated as review blockers. Re-export the package, choose .txt deck when possible, or verify contents with a trusted archive utility before manual review.');
      }

      files[path] = content;
      entries.push({
        path,
        method,
        readable,
        compressedSize,
        uncompressedSize,
      });
      cursor += 46 + nameLength + extraLength + commentLength;
    }

    return {
      files,
      entries,
      unsupportedEntries,
      archiveWarnings,
      archiveGuidance,
      format: file.name.toLowerCase().endsWith('.uaix') ? '.uaix ZIP container' : '.zip container',
    };
  };
  const parseAdvancedPersonaTextDeck = async (file) => {
    const text = await file.text();
    const files = {};
    const lines = text.replace(/\r\n?/g, '\n').split('\n');
    let currentPath = '';
    let currentLines = [];
    const flush = () => {
      if (currentPath) {
        files[currentPath] = currentLines.join('\n').replace(/\n+$/, '');
      }
    };

    lines.forEach((line) => {
      const match = line.match(/^===== ([^=]+) =====$/);
      if (match) {
        flush();
        currentPath = match[1].trim();
        currentLines = [];
        return;
      }

      if (currentPath) {
        currentLines.push(line);
      }
    });
    flush();

    if (!Object.keys(files).length) {
      files['package.txt'] = text;
    }