From bffc0572ef0caab11a6e2aa9a4fdb071cab3c4e7 Mon Sep 17 00:00:00 2001 From: Apocky Date: Mon, 8 Dec 2025 13:24:22 -0700 Subject: [PATCH 1/4] Add files via upload --- web/halo (3).js | 188 +++++++++++++++++++++++++++++++++++ web/index (3).html | 243 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 431 insertions(+) create mode 100644 web/halo (3).js create mode 100644 web/index (3).html diff --git a/web/halo (3).js b/web/halo (3).js new file mode 100644 index 0000000..ffe1758 --- /dev/null +++ b/web/halo (3).js @@ -0,0 +1,188 @@ +// HALO Meta-Oracle skeleton script. +// This script defines the HALO core engine (dice roll), plugin hooks, and local storage. +// The detailed symbol definitions (Tarot cards, runes, I Ching, etc.) and deeper synthesis logic +// should be filled in later. + +(function() { + const STORAGE_KEY_PROFILE = 'halo_profile_v1'; + const STORAGE_KEY_READINGS = 'halo_meta_readings_v1'; + // Replace the placeholder with your actual API Gateway invoke URL once deployed. + const API_URL = 'https://YOUR_API_ID.execute-api.YOUR_REGION.amazonaws.com/readings'; + + // Axis definitions + const AXES = ['Body & Hardware','Mind & Narrative','Heart & Relationships','Domain & Magic']; + const VECTORS = ['Ingress','Grow','Stabilize','Release','Transmute','Witness']; + const TIMELINES = [ + 'Right now','Today','This week','This month','This season','This year', + '1–3 years','3–7 years','7–20 years','Lifetime','Generational','Meta' + ]; + const ARCHETYPES = [ + 'The Fool','The Magician','The Healer','The Warrior','The Shield','The Hermit','The Lover', + 'The Trickster','The Phoenix','The Architect','The Bridge','The Teacher','The Explorer', + 'The Mirror','The Guardian','The Key','The Storm','The Weaver','The Sovereign' + ]; + + // Basic utility to roll a die + function rollDie(sides) { + return Math.floor(Math.random() * sides) + 1; + } + + // Load/save profile + function loadProfile() { + try { + return JSON.parse(localStorage.getItem(STORAGE_KEY_PROFILE)) || {}; + } catch (err) { + return {}; + } + } + + function saveProfile(profile) { + localStorage.setItem(STORAGE_KEY_PROFILE, JSON.stringify(profile)); + } + + // Load/save readings + function loadReadings() { + try { + return JSON.parse(localStorage.getItem(STORAGE_KEY_READINGS)) || []; + } catch (err) { + return []; + } + } + + function saveReadings(readings) { + localStorage.setItem(STORAGE_KEY_READINGS, JSON.stringify(readings)); + } + + // Fire-and-forget sync to server if API_URL is set. + async function syncReadingToServer(reading) { + if (!API_URL || API_URL.includes('YOUR_API_ID')) { + return; + } + try { + const payload = { + userId: reading.user?.name || 'anonymous', + reading + }; + await fetch(API_URL, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(payload) + }); + } catch (err) { + console.warn('Sync failed', err); + } + } + + // Create a new reading + function createReading(question, profile) { + const timestamp = new Date().toISOString(); + const d4 = rollDie(4); + const d6 = rollDie(6); + const d12 = rollDie(12); + const d20 = rollDie(20); + + const reading = { + id: `${Date.now().toString(36)}-${Math.random().toString(16).slice(2,8)}`, + question: question || '', + created_at: timestamp, + halo: { + axis: d4, + vector: d6, + timeline: d12, + archetype: d20, + dice: { d4, d6, d12, d20 } + }, + user: profile, + // plugin results can be added here in the future + }; + + const readings = loadReadings(); + readings.push(reading); + saveReadings(readings); + syncReadingToServer(reading); + return reading; + } + + // Render functions + function renderHistory() { + const historyEl = document.getElementById('history'); + const readings = loadReadings(); + if (!readings.length) { + historyEl.innerHTML = '

No readings yet.

'; + return; + } + const rows = readings.slice().reverse().map(reading => { + const date = new Date(reading.created_at).toLocaleString(); + const axis = AXES[(reading.halo.axis - 1) % AXES.length]; + const vector = VECTORS[(reading.halo.vector - 1) % VECTORS.length]; + const timeline = TIMELINES[(reading.halo.timeline - 1) % TIMELINES.length]; + const archetype = ARCHETYPES[(reading.halo.archetype - 1) % ARCHETYPES.length]; + return ` + + ${date} + ${axis} + ${vector} + ${timeline} + ${archetype} + + `; + }).join(''); + historyEl.innerHTML = ` + + + + + ${rows} +
WhenAxisVectorTimelineArchetype
+ `; + } + + function renderCurrentReading(reading) { + const container = document.getElementById('current-reading'); + if (!reading) { + container.innerHTML = ''; + return; + } + const halo = reading.halo; + container.innerHTML = ` +

HALO Roll

+

Axis: ${AXES[(halo.axis - 1) % AXES.length]} (${halo.dice.d4})

+

Vector: ${VECTORS[(halo.vector - 1) % VECTORS.length]} (${halo.dice.d6})

+

Timeline: ${TIMELINES[(halo.timeline - 1) % TIMELINES.length]} (${halo.dice.d12})

+

Archetype: ${ARCHETYPES[(halo.archetype - 1) % ARCHETYPES.length]} (${halo.dice.d20})

+

This is a bare-bones skeleton. Interpretations and plugin hooks go here.

+ `; + } + + // Initialize UI + function init() { + const profile = loadProfile(); + document.getElementById('profile-name').value = profile.name || ''; + document.getElementById('profile-sun').value = profile.sun || ''; + document.getElementById('profile-moon').value = profile.moon || ''; + document.getElementById('profile-rising').value = profile.rising || ''; + + document.getElementById('save-profile').addEventListener('click', () => { + const p = { + name: document.getElementById('profile-name').value.trim(), + sun: document.getElementById('profile-sun').value.trim(), + moon: document.getElementById('profile-moon').value.trim(), + rising: document.getElementById('profile-rising').value.trim() + }; + saveProfile(p); + }); + + document.getElementById('roll-btn').addEventListener('click', () => { + const q = document.getElementById('question').value.trim(); + const p = loadProfile(); + const r = createReading(q, p); + renderCurrentReading(r); + renderHistory(); + }); + + renderHistory(); + } + + // run + init(); +})(); diff --git a/web/index (3).html b/web/index (3).html new file mode 100644 index 0000000..1cedf32 --- /dev/null +++ b/web/index (3).html @@ -0,0 +1,243 @@ + + + + + + HALO Meta-Oracle – Local Prototype + + + +
+

HALO Meta-Oracle – Local Prototype

+ +
+

1. Profile

+

Optional but helpful—used for tags and flavor text.

+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + Stored only in this browser using localStorage. +
+ +
+

2. Ask HALO

+ + + +
+
+ +
+

3. Past Readings (this device)

+

+ Local Spiritual Blockchain prototype – readings are chained with simple hashes. +

+
+
+
+ + + + From 7b1595a83ddc9bece36bfc1bc83b2e48389829a6 Mon Sep 17 00:00:00 2001 From: Apocky Date: Mon, 8 Dec 2025 13:38:23 -0700 Subject: [PATCH 2/4] Overwrite index.html in master with full replacement. Change request by Apocky on 2025-12-08 20:37:41 UTC. --- index.html | 243 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 243 insertions(+) create mode 100644 index.html diff --git a/index.html b/index.html new file mode 100644 index 0000000..1cedf32 --- /dev/null +++ b/index.html @@ -0,0 +1,243 @@ + + + + + + HALO Meta-Oracle – Local Prototype + + + +
+

HALO Meta-Oracle – Local Prototype

+ +
+

1. Profile

+

Optional but helpful—used for tags and flavor text.

+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + Stored only in this browser using localStorage. +
+ +
+

2. Ask HALO

+ + + +
+
+ +
+

3. Past Readings (this device)

+

+ Local Spiritual Blockchain prototype – readings are chained with simple hashes. +

+
+
+
+ + + + From 4f60a074a06acd5c8c8b207b14c15c7a757eab59 Mon Sep 17 00:00:00 2001 From: Apocky Date: Mon, 8 Dec 2025 13:38:34 -0700 Subject: [PATCH 3/4] Overwrite halo.js on master with skeleton script as requested on 2025-12-08 20:37:53 UTC. --- halo.js | 188 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 188 insertions(+) create mode 100644 halo.js diff --git a/halo.js b/halo.js new file mode 100644 index 0000000..3a73944 --- /dev/null +++ b/halo.js @@ -0,0 +1,188 @@ +// HALO Meta-Oracle skeleton script. +// This script defines the HALO core engine (dice roll), plugin hooks, and local storage. +// The detailed symbol definitions (Tarot cards, runes, I Ching, etc.) and deeper synthesis logic +// should be filled in later. + +(function() { + const STORAGE_KEY_PROFILE = 'halo_profile_v1'; + const STORAGE_KEY_READINGS = 'halo_meta_readings_v1'; + // Replace the placeholder with your actual API Gateway invoke URL once deployed. + const API_URL = 'https://YOUR_API_ID.execute-api.YOUR_REGION.amazonaws.com/readings'; + + // Axis definitions + const AXES = ['Body & Hardware','Mind & Narrative','Heart & Relationships','Domain & Magic']; + const VECTORS = ['Ingress','Grow','Stabilize','Release','Transmute','Witness']; + const TIMELINES = [ + 'Right now','Today','This week','This month','This season','This year', + '1–3 years','3–7 years','7–20 years','Lifetime','Generational','Meta' + ]; + const ARCHETYPES = [ + 'The Fool','The Magician','The Healer','The Warrior','The Shield','The Hermit','The Lover', + 'The Trickster','The Phoenix','The Architect','The Bridge','The Teacher','The Explorer', + 'The Mirror','The Guardian','The Key','The Storm','The Weaver','The Sovereign' + ]; + + // Basic utility to roll a die + function rollDie(sides) { + return Math.floor(Math.random() * sides) + 1; + } + + // Load/save profile + function loadProfile() { + try { + return JSON.parse(localStorage.getItem(STORAGE_KEY_PROFILE)) || {}; + } catch (err) { + return {}; + } + } + + function saveProfile(profile) { + localStorage.setItem(STORAGE_KEY_PROFILE, JSON.stringify(profile)); + } + + // Load/save readings + function loadReadings() { + try { + return JSON.parse(localStorage.getItem(STORAGE_KEY_READINGS)) || []; + } catch (err) { + return []; + } + } + + function saveReadings(readings) { + localStorage.setItem(STORAGE_KEY_READINGS, JSON.stringify(readings)); + } + + // Fire-and-forget sync to server if API_URL is set. + async function syncReadingToServer(reading) { + if (!API_URL || API_URL.includes('YOUR_API_ID')) { + return; + } + try { + const payload = { + userId: reading.user?.name || 'anonymous', + reading + }; + await fetch(API_URL, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(payload) + }); + } catch (err) { + console.warn('Sync failed', err); + } + } + + // Create a new reading + function createReading(question, profile) { + const timestamp = new Date().toISOString(); + const d4 = rollDie(4); + const d6 = rollDie(6); + const d12 = rollDie(12); + const d20 = rollDie(20); + + const reading = { + id: `${Date.now().toString(36)}-${Math.random().toString(16).slice(2,8)}`, + question: question || '', + created_at: timestamp, + halo: { + axis: d4, + vector: d6, + timeline: d12, + archetype: d20, + dice: { d4, d6, d12, d20 } + }, + user: profile, + // plugin results can be added here in the future + }; + + const readings = loadReadings(); + readings.push(reading); + saveReadings(readings); + syncReadingToServer(reading); + return reading; + } + + // Render functions + function renderHistory() { + const historyEl = document.getElementById('history'); + const readings = loadReadings(); + if (!readings.length) { + historyEl.innerHTML = '

No readings yet.

'; + return; + } + const rows = readings.slice().reverse().map(reading => { + const date = new Date(reading.created_at).toLocaleString(); + const axis = AXES[(reading.halo.axis - 1) % AXES.length]; + const vector = VECTORS[(reading.halo.vector - 1) % VECTORS.length]; + const timeline = TIMELINES[(reading.halo.timeline - 1) % TIMELINES.length]; + const archetype = ARCHETYPES[(reading.halo.archetype - 1) % ARCHETYPES.length]; + return ` + + ${date} + ${axis} + ${vector} + ${timeline} + ${archetype} + + `; + }).join(''); + historyEl.innerHTML = ` + + + + + ${rows} +
WhenAxisVectorTimelineArchetype
+ `; + } + + function renderCurrentReading(reading) { + const container = document.getElementById('current-reading'); + if (!reading) { + container.innerHTML = ''; + return; + } + const halo = reading.halo; + container.innerHTML = ` +

HALO Roll

+

Axis: ${AXES[(halo.axis - 1) % AXES.length]} (${halo.dice.d4})

+

Vector: ${VECTORS[(halo.vector - 1) % VECTORS.length]} (${halo.dice.d6})

+

Timeline: ${TIMELINES[(halo.timeline - 1) % TIMELINES.length]} (${halo.dice.d12})

+

Archetype: ${ARCHETYPES[(halo.archetype - 1) % ARCHETYPES.length]} (${halo.dice.d20})

+

This is a bare-bones skeleton. Interpretations and plugin hooks go here.

+ `; + } + + // Initialize UI + function init() { + const profile = loadProfile(); + document.getElementById('profile-name').value = profile.name || ''; + document.getElementById('profile-sun').value = profile.sun || ''; + document.getElementById('profile-moon').value = profile.moon || ''; + document.getElementById('profile-rising').value = profile.rising || ''; + + document.getElementById('save-profile').addEventListener('click', () => { + const p = { + name: document.getElementById('profile-name').value.trim(), + sun: document.getElementById('profile-sun').value.trim(), + moon: document.getElementById('profile-moon').value.trim(), + rising: document.getElementById('profile-rising').value.trim() + }; + saveProfile(p); + }); + + document.getElementById('roll-btn').addEventListener('click', () => { + const q = document.getElementById('question').value.trim(); + const p = loadProfile(); + const r = createReading(q, p); + renderCurrentReading(r); + renderHistory(); + }); + + renderHistory(); + } + + // run + init(); +})(); \ No newline at end of file From d6ccca0ed97b0f0dfbd83f2f80ca06ad56fddc95 Mon Sep 17 00:00:00 2001 From: Apocky Date: Mon, 8 Dec 2025 13:56:13 -0700 Subject: [PATCH 4/4] Add GitHub Actions workflow for ECS deployment This workflow builds and pushes a Docker image to Amazon ECR and deploys it to Amazon ECS when changes are pushed to the master branch. It includes steps for configuring AWS credentials, logging into ECR, building the image, and updating the ECS task definition. --- .github/workflows/aws.yml | 94 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 .github/workflows/aws.yml diff --git a/.github/workflows/aws.yml b/.github/workflows/aws.yml new file mode 100644 index 0000000..3ad415f --- /dev/null +++ b/.github/workflows/aws.yml @@ -0,0 +1,94 @@ +# This workflow will build and push a new container image to Amazon ECR, +# and then will deploy a new task definition to Amazon ECS, when there is a push to the "master" branch. +# +# To use this workflow, you will need to complete the following set-up steps: +# +# 1. Create an ECR repository to store your images. +# For example: `aws ecr create-repository --repository-name my-ecr-repo --region us-east-2`. +# Replace the value of the `ECR_REPOSITORY` environment variable in the workflow below with your repository's name. +# Replace the value of the `AWS_REGION` environment variable in the workflow below with your repository's region. +# +# 2. Create an ECS task definition, an ECS cluster, and an ECS service. +# For example, follow the Getting Started guide on the ECS console: +# https://us-east-2.console.aws.amazon.com/ecs/home?region=us-east-2#/firstRun +# Replace the value of the `ECS_SERVICE` environment variable in the workflow below with the name you set for the Amazon ECS service. +# Replace the value of the `ECS_CLUSTER` environment variable in the workflow below with the name you set for the cluster. +# +# 3. Store your ECS task definition as a JSON file in your repository. +# The format should follow the output of `aws ecs register-task-definition --generate-cli-skeleton`. +# Replace the value of the `ECS_TASK_DEFINITION` environment variable in the workflow below with the path to the JSON file. +# Replace the value of the `CONTAINER_NAME` environment variable in the workflow below with the name of the container +# in the `containerDefinitions` section of the task definition. +# +# 4. Store an IAM user access key in GitHub Actions secrets named `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY`. +# See the documentation for each action used below for the recommended IAM policies for this IAM user, +# and best practices on handling the access key credentials. + +name: Deploy to Amazon ECS + +on: + push: + branches: [ "master" ] + +env: + AWS_REGION: MY_AWS_REGION # set this to your preferred AWS region, e.g. us-west-1 + ECR_REPOSITORY: MY_ECR_REPOSITORY # set this to your Amazon ECR repository name + ECS_SERVICE: MY_ECS_SERVICE # set this to your Amazon ECS service name + ECS_CLUSTER: MY_ECS_CLUSTER # set this to your Amazon ECS cluster name + ECS_TASK_DEFINITION: MY_ECS_TASK_DEFINITION # set this to the path to your Amazon ECS task definition + # file, e.g. .aws/task-definition.json + CONTAINER_NAME: MY_CONTAINER_NAME # set this to the name of the container in the + # containerDefinitions section of your task definition + +permissions: + contents: read + +jobs: + deploy: + name: Deploy + runs-on: ubuntu-latest + environment: production + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: ${{ env.AWS_REGION }} + + - name: Login to Amazon ECR + id: login-ecr + uses: aws-actions/amazon-ecr-login@v1 + + - name: Build, tag, and push image to Amazon ECR + id: build-image + env: + ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }} + IMAGE_TAG: ${{ github.sha }} + run: | + # Build a docker container and + # push it to ECR so that it can + # be deployed to ECS. + docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG . + docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG + echo "image=$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG" >> $GITHUB_OUTPUT + + - name: Fill in the new image ID in the Amazon ECS task definition + id: task-def + uses: aws-actions/amazon-ecs-render-task-definition@v1 + with: + task-definition: ${{ env.ECS_TASK_DEFINITION }} + container-name: ${{ env.CONTAINER_NAME }} + image: ${{ steps.build-image.outputs.image }} + + - name: Deploy Amazon ECS task definition + uses: aws-actions/amazon-ecs-deploy-task-definition@v1 + with: + task-definition: ${{ steps.task-def.outputs.task-definition }} + service: ${{ env.ECS_SERVICE }} + cluster: ${{ env.ECS_CLUSTER }} + wait-for-service-stability: true