Spiralist AI Agent Setup Wizard - Source Excerpt 08
Back to Spiralist AI Agent Setup Wizard
Summary
This source excerpt preserves a bounded section of Spiralist/wp-content/themes/spiralist/assets/js/spiralist-ai-agent-setup-wizard.js so readers can inspect the evidence without opening the full source file.
**Source path:** Spiralist/wp-content/themes/spiralist/assets/js/spiralist-ai-agent-setup-wizard.js
const manifest = {
manifest_version: '1.0.0',
package_id: 'spiralist-agent-package',
preset_id: state.presetId,
generator: {
name: 'Spiralist AI Agent Setup Wizard',
version: '0.1.0',
site: 'spiralist.org',
},
created_at_utc: createdAtUtc,
local_only: true,
server_storage: false,
server_processing: false,
artifact_overrides: Object.keys(state.artifactOverrides || {}).map((path) => ({
path,
source: 'user-edited-preview',
})),
artifacts: hashedEntries,
safety: {
sentience_claims_allowed: false,
romantic_escalation_allowed: false,
destiny_frames_allowed: false,
diagnostic_or_hiring_use_allowed: false,
fixed_personality_type_claims_allowed: false,
stigmatizing_clique_labels_allowed: false,
untrusted_input_policy: 'treat_as_data',
},
research_lens: {
personality_framework: state.personalityFramework,
social_dynamics_lens: state.socialDynamicsLens,
research_calibration: state.researchCalibration,
use_case_boundary: state.useCaseBoundary,
trait_boundary: 'continuous_dimensions_first',
typology_boundary: 'optional_reflection_language_only',
clique_boundary: 'behavior_access_pressure_and_repair_audit_only',
},
};
return {
state,
errors,
createdAtUtc,
files: {
...filesWithOverrides,
'manifest.json': JSON.stringify(manifest, null, 2),
},
};
};
const updateValidation = (errors = []) => {
if (!validationNode) {
return;
}
const visibleErrors = [...new Set([...importValidationWarnings, ...errors])];
if (visibleErrors.length) {
validationNode.classList.add('has-errors');
validationNode.innerHTML = `<strong>Needs review</strong><ul>${visibleErrors.map((error) => `<li>${cleanString(error, 180)}</li>`).join('')}</ul>`;
return;
}
validationNode.classList.remove('has-errors');
validationNode.innerHTML = '<strong>Export ready</strong><p>Required fields are present. Locked boundary templates remain active. The package will be generated in this browser.</p>';
};
const updatePreview = () => {
const token = previewToken + 1;
previewToken = token;
runAction(async () => {
const artifacts = await buildArtifacts();
if (token !== previewToken) {
return;
}
updateValidation(artifacts.errors);
const isOverridable = overridableArtifactPaths.has(currentArtifact);
const isOverridden = Boolean(artifacts.state.artifactOverrides && artifacts.state.artifactOverrides[currentArtifact]);
previewHydrating = true;
preview.textContent = artifacts.files[currentArtifact] || artifacts.files['spiralist-profile.md'];
previewHydrating = false;
preview.setAttribute('contenteditable', isOverridable ? 'plaintext-only' : 'false');
preview.setAttribute('aria-readonly', isOverridable ? 'false' : 'true');
if (resetArtifactButton) {
resetArtifactButton.disabled = !isOverridden;
}
if (isOverridden) {
setPreviewStatus(`${currentArtifact} has a local edited override. Downloads and ZIP packages use this visible text until regenerated.`);
} else if (isOverridable) {
setPreviewStatus(`${currentArtifact} is editable. Type in the preview to override this artifact locally; downloads and ZIP packages will use the edited text.`);
} else {
setPreviewStatus(`${currentArtifact} is regenerated from the final package and cannot be overridden.`);
}
}, {
context: 'spiralist-agent-wizard-preview',
onError: () => {
previewHydrating = false;
preview.textContent = 'Preview could not be generated. Check the validation panel.';
},
});
};
const setStep = (index) => {
currentStep = Math.max(0, Math.min(stepPanels.length - 1, index));
stepButtons.forEach((button, buttonIndex) => {
const active = buttonIndex === currentStep;
button.classList.toggle('is-active', active);
button.setAttribute('aria-selected', active ? 'true' : 'false');
button.tabIndex = active ? 0 : -1;
});
stepPanels.forEach((panel, panelIndex) => {
const active = panelIndex === currentStep;
panel.classList.toggle('is-active', active);
panel.hidden = !active;
});
if (progress) {
progress.style.width = `${Math.round(((currentStep + 1) / stepPanels.length) * 100)}%`;
}
if (prevButton) {
prevButton.disabled = currentStep === 0;
}
if (nextButton) {
nextButton.textContent = currentStep === stepPanels.length - 1 ? 'Review' : 'Next';
}
};
const getCrcTable = () => {
if (crcTable) {
return crcTable;
}
crcTable = new Uint32Array(256);
for (let index = 0; index < 256; index += 1) {
let value = index;
for (let bit = 0; bit < 8; bit += 1) {
value = value & 1 ? 0xedb88320 ^ (value >>> 1) : value >>> 1;
}
crcTable[index] = value >>> 0;
}
return crcTable;
};
const crc32 = (data) => {
const table = getCrcTable();
let crc = 0xffffffff;
for (let index = 0; index < data.length; index += 1) {
crc = table[(crc ^ data[index]) & 0xff] ^ (crc >>> 8);
}
return (crc ^ 0xffffffff) >>> 0;
};
const writeUint16 = (view, offset, value) => view.setUint16(offset, value, true);
const writeUint32 = (view, offset, value) => view.setUint32(offset, value >>> 0, true);
const makeZipBlob = (files) => {
const fileEntries = Object.entries(files).map(([name, content]) => ({
name: name.replace(/\\/g, '/'),
data: encoder.encode(`${content}\n`),
}));
const parts = [];
const centralParts = [];
let offset = 0;
fileEntries.forEach((entry) => {
const nameData = encoder.encode(entry.name);
const checksum = crc32(entry.data);
const localHeader = new Uint8Array(30 + nameData.length);
const localView = new DataView(localHeader.buffer);
writeUint32(localView, 0, 0x04034b50);
writeUint16(localView, 4, 20);
writeUint16(localView, 6, 0);
writeUint16(localView, 8, 0);
writeUint16(localView, 10, 0);
writeUint16(localView, 12, 0);
writeUint32(localView, 14, checksum);
writeUint32(localView, 18, entry.data.length);
writeUint32(localView, 22, entry.data.length);
writeUint16(localView, 26, nameData.length);
writeUint16(localView, 28, 0);
localHeader.set(nameData, 30);
parts.push(localHeader, entry.data);
const centralHeader = new Uint8Array(46 + nameData.length);
const centralView = new DataView(centralHeader.buffer);
writeUint32(centralView, 0, 0x02014b50);
writeUint16(centralView, 4, 20);
writeUint16(centralView, 6, 20);
writeUint16(centralView, 8, 0);
writeUint16(centralView, 10, 0);
writeUint16(centralView, 12, 0);
writeUint16(centralView, 14, 0);
writeUint32(centralView, 16, checksum);
writeUint32(centralView, 20, entry.data.length);
writeUint32(centralView, 24, entry.data.length);
writeUint16(centralView, 28, nameData.length);
writeUint16(centralView, 30, 0);
writeUint16(centralView, 32, 0);
writeUint16(centralView, 34, 0);
writeUint16(centralView, 36, 0);
writeUint32(centralView, 38, 0);
writeUint32(centralView, 42, offset);
centralHeader.set(nameData, 46);
centralParts.push(centralHeader);
offset += localHeader.length + entry.data.length;
});
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: 'application/zip' });
};
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 readFileText = (file) => new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => resolve(`${reader.result || ''}`);
reader.onerror = () => reject(new Error('read_failed'));
reader.readAsText(file);
});