Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 25 additions & 10 deletions .github/workflows/ci-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ jobs:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # 4.2.2
with:
repository: cardstack/boxel
ref: get-catalog-to-run-test

# Checkout this catalog repo into a temp location
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # 4.2.2
Expand Down Expand Up @@ -59,6 +60,16 @@ jobs:

# Copy catalog source files (exclude config files that should stay from monorepo)
rsync -av --exclude='tsconfig.json' --exclude='package.json' --exclude='.realm.json' --exclude='.gitignore' --exclude='tests/' boxel-catalog-src/ packages/catalog-realm/

# Sanity-check daily report module files exist in source and destination
test -f boxel-catalog-src/daily-report-dashboard/daily-report-dashboard.gts
test -f boxel-catalog-src/daily-report-dashboard/policy-manual.gts
test -f boxel-catalog-src/daily-report-dashboard/activity-log.gts
test -f boxel-catalog-src/commands/generate-daily-report.gts
test -f packages/catalog-realm/daily-report-dashboard/daily-report-dashboard.gts
test -f packages/catalog-realm/daily-report-dashboard/policy-manual.gts
test -f packages/catalog-realm/daily-report-dashboard/activity-log.gts
test -f packages/catalog-realm/commands/generate-daily-report.gts

# Copy catalog acceptance and integration tests to host tests directory
rm -rf packages/host/tests/integration
Expand All @@ -68,6 +79,10 @@ jobs:
cp -r boxel-catalog-src/tests/acceptance/* packages/host/tests/acceptance
cp -r boxel-catalog-src/tests/integration/* packages/host/tests/integration
cp -r boxel-catalog-src/tests/helpers/* packages/host/tests/helpers
git checkout -- packages/host/tests/integration/catalog/setup.gts
git checkout -- packages/host/tests/integration/catalog/catalog-runner-test.gts
mkdir -p packages/host/tests/integration/catalog/generated
cp boxel-catalog-src/tests/integration/catalog/modules/daily-report-dashboard.module.gts packages/host/tests/integration/catalog/generated/test-module.gts


# Overwrite the test-wait-for-server script to include catalog server start
Expand All @@ -82,6 +97,14 @@ jobs:
run: NODE_OPTIONS='--max-old-space-size=8192' pnpm build
working-directory: packages/host

- name: Include daily-report modules in host-test catalog subset
run: |
SERVICE_SCRIPT="packages/realm-server/scripts/start-services-for-host-tests.sh"
grep -q '^KEEP_FOLDERS=' "$SERVICE_SCRIPT"
LC_ALL=C perl -0pi -e 's/^KEEP_FOLDERS=.*$/KEEP_FOLDERS="fields catalog-app components commands daily-report-dashboard"/m' "$SERVICE_SCRIPT"
grep '^KEEP_FOLDERS=' "$SERVICE_SCRIPT"
grep -q 'daily-report-dashboard' "$SERVICE_SCRIPT"

- name: Serve boxel-icons
run: pnpm serve &> /tmp/icon-server.log &
working-directory: packages/boxel-icons
Expand Down Expand Up @@ -112,16 +135,8 @@ jobs:
sudo service dbus restart
sudo service upower restart

- name: Run Catalog Acceptance Tests
run: dbus-run-session -- pnpm exec ember exam --path ./dist --filter="Acceptance"
env:
PERCY_GZIP: true
PERCY_TOKEN: ${{ secrets.PERCY_TOKEN_HOST }}
DBUS_SYSTEM_BUS_ADDRESS: unix:path=/run/dbus/system_bus_socket
working-directory: packages/host

- name: Run Catalog Integration Tests
run: dbus-run-session -- pnpm exec ember exam --path ./dist --filter="Integration"
- name: Run Daily Report Dashboard Test Only
run: dbus-run-session -- pnpm exec ember exam --path ./dist --filter="daily-report-dashboard"
env:
PERCY_GZIP: true
PERCY_TOKEN: ${{ secrets.PERCY_TOKEN_HOST }}
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
boxel/
117 changes: 117 additions & 0 deletions commands/generate-daily-report.gts
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import {
CardDef,
field,
contains,
linksTo,
} from 'https://cardstack.com/base/card-api';
import StringField from 'https://cardstack.com/base/string';
import DateField from 'https://cardstack.com/base/date';
import UseAiAssistantCommand from '@cardstack/boxel-host/commands/ai-assistant';
import {
Command,
isResolvedCodeRef,
DEFAULT_CODING_LLM,
} from '@cardstack/runtime-common';
import { SearchCardsByQueryCommand } from '@cardstack/boxel-host/commands/search-cards';
import SaveCardCommand from '@cardstack/boxel-host/commands/save-card';
import { DailyReport } from '../daily-report-dashboard/daily-report';
import { PolicyManual } from '../daily-report-dashboard/policy-manual';
import GetCardCommand from '@cardstack/boxel-host/commands/get-card';

class DailyReportInput extends CardDef {
@field policyManual = linksTo(PolicyManual);
@field realm = contains(StringField);
@field date = contains(DateField);
}
export class GenerateDailyReport extends Command<
typeof DailyReportInput,
undefined
> {
static actionVerb = 'Create';

async getInputType() {
return DailyReportInput;
}

protected async run(input: DailyReportInput): Promise<undefined> {
let { realm, policyManual, date } = input;
if (!realm) {
throw new Error('Realm is required');
}
if (!policyManual) {
throw new Error('Policy manual is required');
}
let activityLogCardType = policyManual.activityLogCardType;
if (!activityLogCardType || !isResolvedCodeRef(activityLogCardType)) {
throw new Error('Activity log card type is required');
}
try {
let searchCommand = new SearchCardsByQueryCommand(this.commandContext);
let targetDate = date || new Date();
let startOfDay = new Date(targetDate);
startOfDay.setHours(0, 0, 0, 0);
let endOfDay = new Date(targetDate);
endOfDay.setHours(23, 59, 59, 999);
let results = await searchCommand.execute({
query: {
filter: {
range: {
timestamp: {
gte: startOfDay.toISOString(),
lte: endOfDay.toISOString(),
},
},
on: {
module: activityLogCardType.module,
name: activityLogCardType.name,
},
},
sort: [
{
by: 'createdAt',
direction: 'desc',
},
],
},
});

let foundCards = await Promise.all(
results.cardIds.map(async (cardId) => {
let card = await new GetCardCommand(this.commandContext).execute({
cardId,
});
return card;
}),
);
let dailyReportCard = new DailyReport({
reportDate: targetDate,
policyManual: policyManual,
summary: foundCards.length > 0 ? 'Analysing...' : 'No Reports Found',
});

await new SaveCardCommand(this.commandContext).execute({
card: dailyReportCard,
realm,
});

let prompt =
'Generate daily report for the selected date from the attached activity log cards using the policy manual and update the attached daily report card';
let skillCardId = new URL(
'../daily-report-dashboard/Skill/daily-report-skill',
import.meta.url,
).href;
let useCommand = new UseAiAssistantCommand(this.commandContext);
await useCommand.execute({
roomId: 'new',
prompt,
attachedCards: [policyManual, dailyReportCard, ...foundCards],
openRoom: true,
llmModel: DEFAULT_CODING_LLM,
llmMode: 'act',
skillCardIds: [skillCardId],
});
} catch (error: any) {
throw new Error(`❌ Failed: ${error.message}`);
}
}
}
26 changes: 26 additions & 0 deletions daily-report-dashboard/Skill/daily-report-skill.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"data": {
"type": "card",
"attributes": {
"instructions": "# Daily Report Generation Skill\n\n## 🚀 AUTOMATION FLOWCHART\n\n### Trigger Recognition\nWhen user says any of these phrases:\n- \"generate today's daily report\"\n- \"create daily report for today\"\n- \"daily report generation\"\n- \"analyze today's activities\"\n- \"make today's report\"\n\n\n### 🧠 Step 1: Intelligent Analysis Engine\n\n#### Pattern Recognition Algorithm\n```\nFOR each activity log:\n - Extract productivity indicators\n - Identify challenge patterns\n - Note success factors\n - Track time allocation\n - Assess team dynamics\n \nAGGREGATE insights:\n - Calculate productivity percentage\n - Identify peak performance periods\n - Cluster related challenges\n - Generate efficiency trends\n```\n\n#### Policy Alignment Check\n```\n- ✅ Activity Logging Protocol compliance\n- ✅ Quality Standards adherence \n- ✅ Time Management principles\n- ✅ Communication requirements\n- ✅ Daily Review Process implementation\n```\n\n### 📝 Step 2: Automated Report Generation\n\n#### Content Structure (Auto-Generated)\n```markdown\n# Daily Summary - [Auto-calculated Date]\n\n## Key Accomplishments\n[Auto-extracted from activity logs]\n\n## Challenges & Solutions\n[Pattern-analyzed obstacles and resolutions]\n\n## Team Coordination\n[Meeting outcomes and communication analysis]\n\n## Technical Status\n[Equipment performance and system status]\n\n## Metrics\n- **Overall Productivity**: [Auto-calculated]%\n- **Equipment Uptime**: [Analyzed]%\n- **Team Effectiveness**: [Assessed level]\n\n# Recommendations for Tomorrow ([Next Date])\n[AI-generated based on patterns and policy alignment]\n```\n\n\n### ✅ Step 3: Success Confirmation\n\n#### Automated Metrics Summary\n```\n🎯 DAILY REPORT GENERATED SUCCESSFULLY\n\n📊 Processing Summary:\n- Activity Logs Found: X entries\n- Time Range: [Start] to [End]\n- Overall Productivity: X%\n- Equipment Uptime: X%\n\n💡 Key Insights:\n- [Top insight from analysis]\n- [Strategic recommendation]\n\n📁 File Created: report-[date].json\n🔄 Ready for tomorrow: [Next date focus]\n```\n\n## 🛡️ Error Handling & Fallbacks\n\n\n### Partial Data Scenarios\n```\nIF some logs found but incomplete:\n GENERATE report with available data\n NOTE limitations in report\n SUGGEST areas for improvement\n```\n\n### Policy Manual Unavailable\n```\nIF operations manual not accessible:\n GENERATE report without policy alignment section\n FOCUS on data-driven insights\n NOTE manual unavailability\n```\n\n",
"commands": [
{
"codeRef": {
"name": "default",
"module": "@cardstack/boxel-host/commands/write-text-file"
},
"requiresApproval": false
}
],
"cardTitle": "Daily Report Generation",
"cardDescription": "Automatically generates comprehensive daily reports by analyzing activity logs, identifying patterns, and creating actionable recommendations for the next day.",
"cardThumbnailURL": null
},
"meta": {
"adoptsFrom": {
"module": "https://cardstack.com/base/skill",
"name": "Skill"
}
}
}
}
Loading
Loading