@iaforged/context-code 1.2.9 → 1.2.12
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/README.md +119 -119
- package/context-bootstrap.js +28 -26
- package/dist/src/QueryEngine.js +394 -327
- package/dist/src/bridge/bridgeUI.js +1 -1
- package/dist/src/buddy/prompt.js +4 -4
- package/dist/src/cli/handlers/auth.js +126 -9
- package/dist/src/cli/print.js +35 -1
- package/dist/src/commands/agent/agent.js +28 -2
- package/dist/src/commands/agent/agentStore.js +8 -1
- package/dist/src/commands/agent/index.js +1 -1
- package/dist/src/commands/bridge-kick.js +9 -9
- package/dist/src/commands/commit.js +34 -34
- package/dist/src/commands/init-verifiers.js +3 -3
- package/dist/src/commands/init.js +88 -88
- package/dist/src/commands/insights.js +787 -787
- package/dist/src/commands/install.js +19 -19
- package/dist/src/commands/login/login.js +21 -12
- package/dist/src/commands/logout/logout.js +9 -0
- package/dist/src/commands/model/model.js +9 -4
- package/dist/src/commands/orchestrate/SwarmUI.js +50 -0
- package/dist/src/commands/orchestrate/index.js +2 -2
- package/dist/src/commands/orchestrate/orchestrate.js +708 -12
- package/dist/src/commands/pr_comments/index.js +33 -33
- package/dist/src/commands/profile/index.js +1 -1
- package/dist/src/commands/profile/profile.js +52 -3
- package/dist/src/commands/provider/index.js +1 -1
- package/dist/src/commands/provider/provider.js +117 -45
- package/dist/src/commands/resumen/index.js +9 -0
- package/dist/src/commands/resumen/resumen.js +29 -0
- package/dist/src/commands/security-review.js +190 -190
- package/dist/src/commands/swarm-auto/index.js +9 -0
- package/dist/src/commands/swarm-auto/swarmAuto.js +111 -0
- package/dist/src/commands/swarm-init/index.js +9 -0
- package/dist/src/commands/swarm-init/swarmInit.js +72 -0
- package/dist/src/commands/team/team.js +39 -6
- package/dist/src/commands.js +14 -0
- package/dist/src/components/LogoV2/CondensedLogo.js +2 -2
- package/dist/src/components/PromptInput/PromptInputQueuedCommands.js +3 -3
- package/dist/src/components/agents/agentFileUtils.js +6 -6
- package/dist/src/components/permissions/hooks.js +5 -5
- package/dist/src/constants/outputStyles.js +83 -83
- package/dist/src/core/agents/blueprints.js +58 -0
- package/dist/src/core/agents/cliAdapter.js +61 -0
- package/dist/src/core/agents/registry.js +93 -0
- package/dist/src/core/agents/runtime.js +4 -0
- package/dist/src/core/agents/runtime.smoke.js +42 -0
- package/dist/src/core/agents/swarm.smoke.js +48 -0
- package/dist/src/core/agents/swarmTools.js +38 -0
- package/dist/src/core/auth/index.js +2 -0
- package/dist/src/core/auth/loginCliAdapter.js +24 -0
- package/dist/src/core/auth/loginCore.js +67 -0
- package/dist/src/core/auth/logoutCliAdapter.js +34 -0
- package/dist/src/core/auth/logoutCore.js +52 -0
- package/dist/src/core/auth/preflight.smoke.js +151 -0
- package/dist/src/core/index.js +21 -0
- package/dist/src/core/mcp/blueprints.js +27 -0
- package/dist/src/core/mcp/common.js +14 -0
- package/dist/src/core/mcp/runtime.js +67 -0
- package/dist/src/core/mcp/runtime.smoke.js +50 -0
- package/dist/src/core/mcp/swarmClient.js +40 -0
- package/dist/src/core/mcp/swarmSetup.js +43 -0
- package/dist/src/core/providers/cliAdapter.js +39 -0
- package/dist/src/core/providers/contracts.js +1 -0
- package/dist/src/core/providers/index.js +3 -0
- package/dist/src/core/providers/llmCore.js +123 -0
- package/dist/src/core/providers/providerCore.js +141 -0
- package/dist/src/core/providers/providerModelCompatibility.js +98 -0
- package/dist/src/core/providers/providerParitySmoke.js +83 -0
- package/dist/src/core/providers/providerProfileModelSmoke.js +80 -0
- package/dist/src/core/query/contracts.js +1 -0
- package/dist/src/core/query/runtime.js +117 -0
- package/dist/src/core/query/runtime.smoke.js +39 -0
- package/dist/src/core/query/timelineThinking.smoke.js +25 -0
- package/dist/src/core/query/wiring.smoke.js +76 -0
- package/dist/src/core/skills/cliAdapter.js +38 -0
- package/dist/src/core/skills/index.js +52 -0
- package/dist/src/core/skills/runtime.smoke.js +53 -0
- package/dist/src/core/tasks/runtime.js +205 -0
- package/dist/src/core/tasks/runtime.smoke.js +63 -0
- package/dist/src/core/tasks/sdkAdapter.js +4 -0
- package/dist/src/core/tools/contracts.js +3 -0
- package/dist/src/core/tools/fileResolution.js +112 -0
- package/dist/src/core/tools/fileResolution.smoke.js +33 -0
- package/dist/src/core/tools/filesCore.js +51 -0
- package/dist/src/core/tools/filesCore.smoke.js +108 -0
- package/dist/src/core/tools/gitCore.js +20 -0
- package/dist/src/core/tools/imageParity.smoke.js +36 -0
- package/dist/src/core/tools/notebookParity.smoke.js +68 -0
- package/dist/src/core/tools/registry.js +22 -0
- package/dist/src/core/tools/runtime.smoke.js +32 -0
- package/dist/src/core/tools/shellCore.js +60 -0
- package/dist/src/core/types/agentContext.js +9 -0
- package/dist/src/core/types/auth.js +3 -0
- package/dist/src/core/types/command.js +13 -0
- package/dist/src/core/types/provider.js +3 -0
- package/dist/src/core/types/sdkEvent.js +10 -0
- package/dist/src/core/types/swarm.js +1 -0
- package/dist/src/cost-tracker.js +3 -3
- package/dist/src/hooks/useAwaySummary.js +22 -9
- package/dist/src/main.js +32 -2
- package/dist/src/screens/REPL.js +9 -0
- package/dist/src/services/AgentSummary/agentSummary.js +10 -10
- package/dist/src/services/autoDream/autoDream.js +5 -5
- package/dist/src/services/autoDream/consolidationPrompt.js +49 -49
- package/dist/src/services/compact/prompt.js +238 -238
- package/dist/src/services/limits/sessionCounter.js +17 -17
- package/dist/src/services/mcp/client.js +27 -1
- package/dist/src/services/orchestration/execution/AgentTaskExecutor.js +39 -20
- package/dist/src/services/orchestration/execution/OrchestrationExecutionRuntime.js +65 -58
- package/dist/src/skills/bundled/loop.js +57 -57
- package/dist/src/skills/bundled/remember.js +53 -53
- package/dist/src/skills/bundled/simplify.js +49 -49
- package/dist/src/skills/bundled/skillify.js +2 -2
- package/dist/src/state/onChangeAppState.js +6 -0
- package/dist/src/tasks/LocalAgentTask/LocalAgentTask.js +5 -5
- package/dist/src/tasks/LocalMainSessionTask.js +5 -5
- package/dist/src/tasks/LocalShellTask/LocalShellTask.js +13 -13
- package/dist/src/tools/AgentTool/forkSubagent.js +25 -25
- package/dist/src/tools/AskUserQuestionTool/prompt.js +29 -29
- package/dist/src/tools/BashTool/BashTool.js +27 -2
- package/dist/src/tools/BriefTool/prompt.js +14 -14
- package/dist/src/tools/EnterPlanModeTool/EnterPlanModeTool.js +12 -12
- package/dist/src/tools/EnterPlanModeTool/prompt.js +140 -140
- package/dist/src/tools/ExitPlanModeTool/ExitPlanModeV2Tool.js +18 -18
- package/dist/src/tools/ExitPlanModeTool/prompt.js +23 -23
- package/dist/src/tools/ExitWorktreeTool/prompt.js +29 -29
- package/dist/src/tools/FileEditTool/prompt.js +7 -7
- package/dist/src/tools/FileReadTool/FileReadTool.js +18 -1
- package/dist/src/tools/FileWriteTool/prompt.js +6 -6
- package/dist/src/tools/GlobTool/prompt.js +4 -4
- package/dist/src/tools/GrepTool/prompt.js +10 -10
- package/dist/src/tools/LSPTool/prompt.js +18 -18
- package/dist/src/tools/ListMcpResourcesTool/prompt.js +15 -15
- package/dist/src/tools/PowerShellTool/PowerShellTool.js +25 -2
- package/dist/src/tools/ReadMcpResourceTool/prompt.js +13 -13
- package/dist/src/tools/SendMessageTool/prompt.js +36 -36
- package/dist/src/tools/SkillTool/prompt.js +21 -21
- package/dist/src/tools/SleepTool/prompt.js +10 -10
- package/dist/src/tools/TaskCreateTool/prompt.js +41 -41
- package/dist/src/tools/TaskGetTool/prompt.js +21 -21
- package/dist/src/tools/TaskListTool/prompt.js +30 -30
- package/dist/src/tools/TaskOutputTool/TaskOutputTool.js +8 -8
- package/dist/src/tools/TaskStopTool/prompt.js +5 -5
- package/dist/src/tools/TaskUpdateTool/prompt.js +74 -74
- package/dist/src/tools/TodoWriteTool/prompt.js +178 -178
- package/dist/src/tools/ToolSearchTool/prompt.js +9 -9
- package/dist/src/tools/WebFetchTool/WebFetchTool.js +9 -9
- package/dist/src/tools/WebFetchTool/prompt.js +31 -31
- package/dist/src/tools/WebSearchTool/prompt.js +26 -26
- package/dist/src/utils/agentContext.js +2 -0
- package/dist/src/utils/agenticSessionSearch.js +38 -38
- package/dist/src/utils/config.js +2 -0
- package/dist/src/utils/genericProcessUtils.js +21 -21
- package/dist/src/utils/heapDumpService.js +4 -4
- package/dist/src/utils/mcpValidation.js +2 -2
- package/dist/src/utils/model/modelStrings.js +1 -1
- package/dist/src/utils/model/providers.js +5 -0
- package/dist/src/utils/orchestration/store/providerAgentStore.js +22 -22
- package/dist/src/utils/orchestration/store/providerWorkspaceStore.js +10 -10
- package/dist/src/utils/orchestration/store/runStore.js +68 -68
- package/dist/src/utils/orchestration/store/teamStore.js +28 -28
- package/dist/src/utils/permissions/permissionExplainer.js +6 -6
- package/dist/src/utils/permissions/permissionsDb.js +43 -43
- package/dist/src/utils/sdkEventQueue.js +2 -0
- package/dist/src/utils/secureStorage/sqliteStorage.js +12 -12
- package/dist/src/utils/standardMcp/common.js +15 -0
- package/dist/src/utils/standardMcp/setup.js +52 -0
- package/dist/src/utils/swarm/teammatePromptAddendum.js +10 -10
- package/dist/src/utils/task/framework.js +6 -6
- package/package.json +1 -1
- package/dist/src/commands/usage/index.js +0 -7
- package/dist/src/commands/usage/usage.js +0 -5
|
@@ -246,32 +246,32 @@ function getFacetsDir() {
|
|
|
246
246
|
function getSessionMetaDir() {
|
|
247
247
|
return join(getDataDir(), 'session-meta');
|
|
248
248
|
}
|
|
249
|
-
const FACET_EXTRACTION_PROMPT = `Analyze this Context Code session and extract structured facets.
|
|
250
|
-
|
|
251
|
-
CRITICAL GUIDELINES:
|
|
252
|
-
|
|
253
|
-
1. **goal_categories**: Count ONLY what the USER explicitly asked for.
|
|
254
|
-
- DO NOT count Claude's autonomous codebase exploration
|
|
255
|
-
- DO NOT count work Claude decided to do on its own
|
|
256
|
-
- ONLY count when user says "can you...", "please...", "I need...", "let's..."
|
|
257
|
-
|
|
258
|
-
2. **user_satisfaction_counts**: Base ONLY on explicit user signals.
|
|
259
|
-
- "Yay!", "great!", "perfect!" → happy
|
|
260
|
-
- "thanks", "looks good", "that works" → satisfied
|
|
261
|
-
- "ok, now let's..." (continuing without complaint) → likely_satisfied
|
|
262
|
-
- "that's not right", "try again" → dissatisfied
|
|
263
|
-
- "this is broken", "I give up" → frustrated
|
|
264
|
-
|
|
265
|
-
3. **friction_counts**: Be specific about what went wrong.
|
|
266
|
-
- misunderstood_request: Claude interpreted incorrectly
|
|
267
|
-
- wrong_approach: Right goal, wrong solution method
|
|
268
|
-
- buggy_code: Code didn't work correctly
|
|
269
|
-
- user_rejected_action: User said no/stop to a tool call
|
|
270
|
-
- excessive_changes: Over-engineered or changed too much
|
|
271
|
-
|
|
272
|
-
4. If very short or just warmup, use warmup_minimal for goal_category
|
|
273
|
-
|
|
274
|
-
SESSION:
|
|
249
|
+
const FACET_EXTRACTION_PROMPT = `Analyze this Context Code session and extract structured facets.
|
|
250
|
+
|
|
251
|
+
CRITICAL GUIDELINES:
|
|
252
|
+
|
|
253
|
+
1. **goal_categories**: Count ONLY what the USER explicitly asked for.
|
|
254
|
+
- DO NOT count Claude's autonomous codebase exploration
|
|
255
|
+
- DO NOT count work Claude decided to do on its own
|
|
256
|
+
- ONLY count when user says "can you...", "please...", "I need...", "let's..."
|
|
257
|
+
|
|
258
|
+
2. **user_satisfaction_counts**: Base ONLY on explicit user signals.
|
|
259
|
+
- "Yay!", "great!", "perfect!" → happy
|
|
260
|
+
- "thanks", "looks good", "that works" → satisfied
|
|
261
|
+
- "ok, now let's..." (continuing without complaint) → likely_satisfied
|
|
262
|
+
- "that's not right", "try again" → dissatisfied
|
|
263
|
+
- "this is broken", "I give up" → frustrated
|
|
264
|
+
|
|
265
|
+
3. **friction_counts**: Be specific about what went wrong.
|
|
266
|
+
- misunderstood_request: Claude interpreted incorrectly
|
|
267
|
+
- wrong_approach: Right goal, wrong solution method
|
|
268
|
+
- buggy_code: Code didn't work correctly
|
|
269
|
+
- user_rejected_action: User said no/stop to a tool call
|
|
270
|
+
- excessive_changes: Over-engineered or changed too much
|
|
271
|
+
|
|
272
|
+
4. If very short or just warmup, use warmup_minimal for goal_category
|
|
273
|
+
|
|
274
|
+
SESSION:
|
|
275
275
|
`;
|
|
276
276
|
// ============================================================================
|
|
277
277
|
// Helper Functions
|
|
@@ -627,15 +627,15 @@ function formatTranscriptForFacets(log) {
|
|
|
627
627
|
}
|
|
628
628
|
return lines.join('\n');
|
|
629
629
|
}
|
|
630
|
-
const SUMMARIZE_CHUNK_PROMPT = `Summarize this portion of a Context Code session transcript. Focus on:
|
|
631
|
-
1. What the user asked for
|
|
632
|
-
2. What Claude did (tools used, files modified)
|
|
633
|
-
3. Any friction or issues
|
|
634
|
-
4. The outcome
|
|
635
|
-
|
|
636
|
-
Keep it concise - 3-5 sentences. Preserve specific details like file names, error messages, and user feedback.
|
|
637
|
-
|
|
638
|
-
TRANSCRIPT CHUNK:
|
|
630
|
+
const SUMMARIZE_CHUNK_PROMPT = `Summarize this portion of a Context Code session transcript. Focus on:
|
|
631
|
+
1. What the user asked for
|
|
632
|
+
2. What Claude did (tools used, files modified)
|
|
633
|
+
3. Any friction or issues
|
|
634
|
+
4. The outcome
|
|
635
|
+
|
|
636
|
+
Keep it concise - 3-5 sentences. Preserve specific details like file names, error messages, and user feedback.
|
|
637
|
+
|
|
638
|
+
TRANSCRIPT CHUNK:
|
|
639
639
|
`;
|
|
640
640
|
async function summarizeTranscriptChunk(chunk) {
|
|
641
641
|
try {
|
|
@@ -749,20 +749,20 @@ async function extractFacetsFromAPI(log, sessionId) {
|
|
|
749
749
|
// Use summarization for long transcripts
|
|
750
750
|
const transcript = await formatTranscriptWithSummarization(log);
|
|
751
751
|
// Build prompt asking for JSON directly (no tool use)
|
|
752
|
-
const jsonPrompt = `${FACET_EXTRACTION_PROMPT}${transcript}
|
|
753
|
-
|
|
754
|
-
RESPOND WITH ONLY A VALID JSON OBJECT matching this schema:
|
|
755
|
-
{
|
|
756
|
-
"underlying_goal": "What the user fundamentally wanted to achieve",
|
|
757
|
-
"goal_categories": {"category_name": count, ...},
|
|
758
|
-
"outcome": "fully_achieved|mostly_achieved|partially_achieved|not_achieved|unclear_from_transcript",
|
|
759
|
-
"user_satisfaction_counts": {"level": count, ...},
|
|
760
|
-
"claude_helpfulness": "unhelpful|slightly_helpful|moderately_helpful|very_helpful|essential",
|
|
761
|
-
"session_type": "single_task|multi_task|iterative_refinement|exploration|quick_question",
|
|
762
|
-
"friction_counts": {"friction_type": count, ...},
|
|
763
|
-
"friction_detail": "One sentence describing friction or empty",
|
|
764
|
-
"primary_success": "none|fast_accurate_search|correct_code_edits|good_explanations|proactive_help|multi_file_changes|good_debugging",
|
|
765
|
-
"brief_summary": "One sentence: what user wanted and whether they got it"
|
|
752
|
+
const jsonPrompt = `${FACET_EXTRACTION_PROMPT}${transcript}
|
|
753
|
+
|
|
754
|
+
RESPOND WITH ONLY A VALID JSON OBJECT matching this schema:
|
|
755
|
+
{
|
|
756
|
+
"underlying_goal": "What the user fundamentally wanted to achieve",
|
|
757
|
+
"goal_categories": {"category_name": count, ...},
|
|
758
|
+
"outcome": "fully_achieved|mostly_achieved|partially_achieved|not_achieved|unclear_from_transcript",
|
|
759
|
+
"user_satisfaction_counts": {"level": count, ...},
|
|
760
|
+
"claude_helpfulness": "unhelpful|slightly_helpful|moderately_helpful|very_helpful|essential",
|
|
761
|
+
"session_type": "single_task|multi_task|iterative_refinement|exploration|quick_question",
|
|
762
|
+
"friction_counts": {"friction_type": count, ...},
|
|
763
|
+
"friction_detail": "One sentence describing friction or empty",
|
|
764
|
+
"primary_success": "none|fast_accurate_search|correct_code_edits|good_explanations|proactive_help|multi_file_changes|good_debugging",
|
|
765
|
+
"brief_summary": "One sentence: what user wanted and whether they got it"
|
|
766
766
|
}`;
|
|
767
767
|
const result = await queryWithModel({
|
|
768
768
|
systemPrompt: asSystemPrompt([]),
|
|
@@ -1022,114 +1022,114 @@ function aggregateData(sessions, facets) {
|
|
|
1022
1022
|
const INSIGHT_SECTIONS = [
|
|
1023
1023
|
{
|
|
1024
1024
|
name: 'project_areas',
|
|
1025
|
-
prompt: `Analyze this Context Code usage data and identify project areas.
|
|
1026
|
-
|
|
1027
|
-
RESPOND WITH ONLY A VALID JSON OBJECT:
|
|
1028
|
-
{
|
|
1029
|
-
"areas": [
|
|
1030
|
-
{"name": "Area name", "session_count": N, "description": "2-3 sentences about what was worked on and how Context Code was used."}
|
|
1031
|
-
]
|
|
1032
|
-
}
|
|
1033
|
-
|
|
1025
|
+
prompt: `Analyze this Context Code usage data and identify project areas.
|
|
1026
|
+
|
|
1027
|
+
RESPOND WITH ONLY A VALID JSON OBJECT:
|
|
1028
|
+
{
|
|
1029
|
+
"areas": [
|
|
1030
|
+
{"name": "Area name", "session_count": N, "description": "2-3 sentences about what was worked on and how Context Code was used."}
|
|
1031
|
+
]
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
1034
|
Include 4-5 areas. Skip internal CC operations.`,
|
|
1035
1035
|
maxTokens: 8192,
|
|
1036
1036
|
},
|
|
1037
1037
|
{
|
|
1038
1038
|
name: 'interaction_style',
|
|
1039
|
-
prompt: `Analyze this Context Code usage data and describe the user's interaction style.
|
|
1040
|
-
|
|
1041
|
-
RESPOND WITH ONLY A VALID JSON OBJECT:
|
|
1042
|
-
{
|
|
1043
|
-
"narrative": "2-3 paragraphs analyzing HOW the user interacts with Context Code. Use second person 'you'. Describe patterns: iterate quickly vs detailed upfront specs? Interrupt often or let Claude run? Include specific examples. Use **bold** for key insights.",
|
|
1044
|
-
"key_pattern": "One sentence summary of most distinctive interaction style"
|
|
1039
|
+
prompt: `Analyze this Context Code usage data and describe the user's interaction style.
|
|
1040
|
+
|
|
1041
|
+
RESPOND WITH ONLY A VALID JSON OBJECT:
|
|
1042
|
+
{
|
|
1043
|
+
"narrative": "2-3 paragraphs analyzing HOW the user interacts with Context Code. Use second person 'you'. Describe patterns: iterate quickly vs detailed upfront specs? Interrupt often or let Claude run? Include specific examples. Use **bold** for key insights.",
|
|
1044
|
+
"key_pattern": "One sentence summary of most distinctive interaction style"
|
|
1045
1045
|
}`,
|
|
1046
1046
|
maxTokens: 8192,
|
|
1047
1047
|
},
|
|
1048
1048
|
{
|
|
1049
1049
|
name: 'what_works',
|
|
1050
|
-
prompt: `Analyze this Context Code usage data and identify what's working well for this user. Use second person ("you").
|
|
1051
|
-
|
|
1052
|
-
RESPOND WITH ONLY A VALID JSON OBJECT:
|
|
1053
|
-
{
|
|
1054
|
-
"intro": "1 sentence of context",
|
|
1055
|
-
"impressive_workflows": [
|
|
1056
|
-
{"title": "Short title (3-6 words)", "description": "2-3 sentences describing the impressive workflow or approach. Use 'you' not 'the user'."}
|
|
1057
|
-
]
|
|
1058
|
-
}
|
|
1059
|
-
|
|
1050
|
+
prompt: `Analyze this Context Code usage data and identify what's working well for this user. Use second person ("you").
|
|
1051
|
+
|
|
1052
|
+
RESPOND WITH ONLY A VALID JSON OBJECT:
|
|
1053
|
+
{
|
|
1054
|
+
"intro": "1 sentence of context",
|
|
1055
|
+
"impressive_workflows": [
|
|
1056
|
+
{"title": "Short title (3-6 words)", "description": "2-3 sentences describing the impressive workflow or approach. Use 'you' not 'the user'."}
|
|
1057
|
+
]
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
1060
|
Include 3 impressive workflows.`,
|
|
1061
1061
|
maxTokens: 8192,
|
|
1062
1062
|
},
|
|
1063
1063
|
{
|
|
1064
1064
|
name: 'friction_analysis',
|
|
1065
|
-
prompt: `Analyze this Context Code usage data and identify friction points for this user. Use second person ("you").
|
|
1066
|
-
|
|
1067
|
-
RESPOND WITH ONLY A VALID JSON OBJECT:
|
|
1068
|
-
{
|
|
1069
|
-
"intro": "1 sentence summarizing friction patterns",
|
|
1070
|
-
"categories": [
|
|
1071
|
-
{"category": "Concrete category name", "description": "1-2 sentences explaining this category and what could be done differently. Use 'you' not 'the user'.", "examples": ["Specific example with consequence", "Another example"]}
|
|
1072
|
-
]
|
|
1073
|
-
}
|
|
1074
|
-
|
|
1065
|
+
prompt: `Analyze this Context Code usage data and identify friction points for this user. Use second person ("you").
|
|
1066
|
+
|
|
1067
|
+
RESPOND WITH ONLY A VALID JSON OBJECT:
|
|
1068
|
+
{
|
|
1069
|
+
"intro": "1 sentence summarizing friction patterns",
|
|
1070
|
+
"categories": [
|
|
1071
|
+
{"category": "Concrete category name", "description": "1-2 sentences explaining this category and what could be done differently. Use 'you' not 'the user'.", "examples": ["Specific example with consequence", "Another example"]}
|
|
1072
|
+
]
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
1075
|
Include 3 friction categories with 2 examples each.`,
|
|
1076
1076
|
maxTokens: 8192,
|
|
1077
1077
|
},
|
|
1078
1078
|
{
|
|
1079
1079
|
name: 'suggestions',
|
|
1080
|
-
prompt: `Analyze this Context Code usage data and suggest improvements.
|
|
1081
|
-
|
|
1082
|
-
## CC FEATURES REFERENCE (pick from these for features_to_try):
|
|
1083
|
-
1. **MCP Servers**: Connect Claude to external tools, databases, and APIs via Model Context Protocol.
|
|
1084
|
-
- How to use: Run \`claude mcp add <server-name> -- <command>\`
|
|
1085
|
-
- Good for: database queries, Slack integration, GitHub issue lookup, connecting to internal APIs
|
|
1086
|
-
|
|
1087
|
-
2. **Custom Skills**: Reusable prompts you define as markdown files that run with a single /command.
|
|
1088
|
-
- How to use: Create \`.claude/skills/commit/SKILL.md\` with instructions. Then type \`/commit\` to run it.
|
|
1089
|
-
- Good for: repetitive workflows - /commit, /review, /test, /deploy, /pr, or complex multi-step workflows
|
|
1090
|
-
|
|
1091
|
-
3. **Hooks**: Shell commands that auto-run at specific lifecycle events.
|
|
1092
|
-
- How to use: Add to \`.claude/settings.json\` under "hooks" key.
|
|
1093
|
-
- Good for: auto-formatting code, running type checks, enforcing conventions
|
|
1094
|
-
|
|
1095
|
-
4. **Headless Mode**: Run Claude non-interactively from scripts and CI/CD.
|
|
1096
|
-
- How to use: \`claude -p "fix lint errors" --allowedTools "Edit,Read,Bash"\`
|
|
1097
|
-
- Good for: CI/CD integration, batch code fixes, automated reviews
|
|
1098
|
-
|
|
1099
|
-
5. **Task Agents**: Claude spawns focused sub-agents for complex exploration or parallel work.
|
|
1100
|
-
- How to use: Claude auto-invokes when helpful, or ask "use an agent to explore X"
|
|
1101
|
-
- Good for: codebase exploration, understanding complex systems
|
|
1102
|
-
|
|
1103
|
-
RESPOND WITH ONLY A VALID JSON OBJECT:
|
|
1104
|
-
{
|
|
1105
|
-
"claude_md_additions": [
|
|
1106
|
-
{"addition": "A specific line or block to add to CLAUDE.md based on workflow patterns. E.g., 'Always run tests after modifying auth-related files'", "why": "1 sentence explaining why this would help based on actual sessions", "prompt_scaffold": "Instructions for where to add this in CLAUDE.md. E.g., 'Add under ## Testing section'"}
|
|
1107
|
-
],
|
|
1108
|
-
"features_to_try": [
|
|
1109
|
-
{"feature": "Feature name from CC FEATURES REFERENCE above", "one_liner": "What it does", "why_for_you": "Why this would help YOU based on your sessions", "example_code": "Actual command or config to copy"}
|
|
1110
|
-
],
|
|
1111
|
-
"usage_patterns": [
|
|
1112
|
-
{"title": "Short title", "suggestion": "1-2 sentence summary", "detail": "3-4 sentences explaining how this applies to YOUR work", "copyable_prompt": "A specific prompt to copy and try"}
|
|
1113
|
-
]
|
|
1114
|
-
}
|
|
1115
|
-
|
|
1116
|
-
IMPORTANT for claude_md_additions: PRIORITIZE instructions that appear MULTIPLE TIMES in the user data. If user told Claude the same thing in 2+ sessions (e.g., 'always run tests', 'use TypeScript'), that's a PRIME candidate - they shouldn't have to repeat themselves.
|
|
1117
|
-
|
|
1080
|
+
prompt: `Analyze this Context Code usage data and suggest improvements.
|
|
1081
|
+
|
|
1082
|
+
## CC FEATURES REFERENCE (pick from these for features_to_try):
|
|
1083
|
+
1. **MCP Servers**: Connect Claude to external tools, databases, and APIs via Model Context Protocol.
|
|
1084
|
+
- How to use: Run \`claude mcp add <server-name> -- <command>\`
|
|
1085
|
+
- Good for: database queries, Slack integration, GitHub issue lookup, connecting to internal APIs
|
|
1086
|
+
|
|
1087
|
+
2. **Custom Skills**: Reusable prompts you define as markdown files that run with a single /command.
|
|
1088
|
+
- How to use: Create \`.claude/skills/commit/SKILL.md\` with instructions. Then type \`/commit\` to run it.
|
|
1089
|
+
- Good for: repetitive workflows - /commit, /review, /test, /deploy, /pr, or complex multi-step workflows
|
|
1090
|
+
|
|
1091
|
+
3. **Hooks**: Shell commands that auto-run at specific lifecycle events.
|
|
1092
|
+
- How to use: Add to \`.claude/settings.json\` under "hooks" key.
|
|
1093
|
+
- Good for: auto-formatting code, running type checks, enforcing conventions
|
|
1094
|
+
|
|
1095
|
+
4. **Headless Mode**: Run Claude non-interactively from scripts and CI/CD.
|
|
1096
|
+
- How to use: \`claude -p "fix lint errors" --allowedTools "Edit,Read,Bash"\`
|
|
1097
|
+
- Good for: CI/CD integration, batch code fixes, automated reviews
|
|
1098
|
+
|
|
1099
|
+
5. **Task Agents**: Claude spawns focused sub-agents for complex exploration or parallel work.
|
|
1100
|
+
- How to use: Claude auto-invokes when helpful, or ask "use an agent to explore X"
|
|
1101
|
+
- Good for: codebase exploration, understanding complex systems
|
|
1102
|
+
|
|
1103
|
+
RESPOND WITH ONLY A VALID JSON OBJECT:
|
|
1104
|
+
{
|
|
1105
|
+
"claude_md_additions": [
|
|
1106
|
+
{"addition": "A specific line or block to add to CLAUDE.md based on workflow patterns. E.g., 'Always run tests after modifying auth-related files'", "why": "1 sentence explaining why this would help based on actual sessions", "prompt_scaffold": "Instructions for where to add this in CLAUDE.md. E.g., 'Add under ## Testing section'"}
|
|
1107
|
+
],
|
|
1108
|
+
"features_to_try": [
|
|
1109
|
+
{"feature": "Feature name from CC FEATURES REFERENCE above", "one_liner": "What it does", "why_for_you": "Why this would help YOU based on your sessions", "example_code": "Actual command or config to copy"}
|
|
1110
|
+
],
|
|
1111
|
+
"usage_patterns": [
|
|
1112
|
+
{"title": "Short title", "suggestion": "1-2 sentence summary", "detail": "3-4 sentences explaining how this applies to YOUR work", "copyable_prompt": "A specific prompt to copy and try"}
|
|
1113
|
+
]
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
IMPORTANT for claude_md_additions: PRIORITIZE instructions that appear MULTIPLE TIMES in the user data. If user told Claude the same thing in 2+ sessions (e.g., 'always run tests', 'use TypeScript'), that's a PRIME candidate - they shouldn't have to repeat themselves.
|
|
1117
|
+
|
|
1118
1118
|
IMPORTANT for features_to_try: Pick 2-3 from the CC FEATURES REFERENCE above. Include 2-3 items for each category.`,
|
|
1119
1119
|
maxTokens: 8192,
|
|
1120
1120
|
},
|
|
1121
1121
|
{
|
|
1122
1122
|
name: 'on_the_horizon',
|
|
1123
|
-
prompt: `Analyze this Context Code usage data and identify future opportunities.
|
|
1124
|
-
|
|
1125
|
-
RESPOND WITH ONLY A VALID JSON OBJECT:
|
|
1126
|
-
{
|
|
1127
|
-
"intro": "1 sentence about evolving AI-assisted development",
|
|
1128
|
-
"opportunities": [
|
|
1129
|
-
{"title": "Short title (4-8 words)", "whats_possible": "2-3 ambitious sentences about autonomous workflows", "how_to_try": "1-2 sentences mentioning relevant tooling", "copyable_prompt": "Detailed prompt to try"}
|
|
1130
|
-
]
|
|
1131
|
-
}
|
|
1132
|
-
|
|
1123
|
+
prompt: `Analyze this Context Code usage data and identify future opportunities.
|
|
1124
|
+
|
|
1125
|
+
RESPOND WITH ONLY A VALID JSON OBJECT:
|
|
1126
|
+
{
|
|
1127
|
+
"intro": "1 sentence about evolving AI-assisted development",
|
|
1128
|
+
"opportunities": [
|
|
1129
|
+
{"title": "Short title (4-8 words)", "whats_possible": "2-3 ambitious sentences about autonomous workflows", "how_to_try": "1-2 sentences mentioning relevant tooling", "copyable_prompt": "Detailed prompt to try"}
|
|
1130
|
+
]
|
|
1131
|
+
}
|
|
1132
|
+
|
|
1133
1133
|
Include 3 opportunities. Think BIG - autonomous workflows, parallel agents, iterating against tests.`,
|
|
1134
1134
|
maxTokens: 8192,
|
|
1135
1135
|
},
|
|
@@ -1137,29 +1137,29 @@ Include 3 opportunities. Think BIG - autonomous workflows, parallel agents, iter
|
|
|
1137
1137
|
? [
|
|
1138
1138
|
{
|
|
1139
1139
|
name: 'cc_team_improvements',
|
|
1140
|
-
prompt: `Analyze this Context Code usage data and suggest product improvements for the CC team.
|
|
1141
|
-
|
|
1142
|
-
RESPOND WITH ONLY A VALID JSON OBJECT:
|
|
1143
|
-
{
|
|
1144
|
-
"improvements": [
|
|
1145
|
-
{"title": "Product/tooling improvement", "detail": "3-4 sentences describing the improvement", "evidence": "3-4 sentences with specific session examples"}
|
|
1146
|
-
]
|
|
1147
|
-
}
|
|
1148
|
-
|
|
1140
|
+
prompt: `Analyze this Context Code usage data and suggest product improvements for the CC team.
|
|
1141
|
+
|
|
1142
|
+
RESPOND WITH ONLY A VALID JSON OBJECT:
|
|
1143
|
+
{
|
|
1144
|
+
"improvements": [
|
|
1145
|
+
{"title": "Product/tooling improvement", "detail": "3-4 sentences describing the improvement", "evidence": "3-4 sentences with specific session examples"}
|
|
1146
|
+
]
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1149
1149
|
Include 2-3 improvements based on friction patterns observed.`,
|
|
1150
1150
|
maxTokens: 8192,
|
|
1151
1151
|
},
|
|
1152
1152
|
{
|
|
1153
1153
|
name: 'model_behavior_improvements',
|
|
1154
|
-
prompt: `Analyze this Context Code usage data and suggest model behavior improvements.
|
|
1155
|
-
|
|
1156
|
-
RESPOND WITH ONLY A VALID JSON OBJECT:
|
|
1157
|
-
{
|
|
1158
|
-
"improvements": [
|
|
1159
|
-
{"title": "Model behavior change", "detail": "3-4 sentences describing what the model should do differently", "evidence": "3-4 sentences with specific examples"}
|
|
1160
|
-
]
|
|
1161
|
-
}
|
|
1162
|
-
|
|
1154
|
+
prompt: `Analyze this Context Code usage data and suggest model behavior improvements.
|
|
1155
|
+
|
|
1156
|
+
RESPOND WITH ONLY A VALID JSON OBJECT:
|
|
1157
|
+
{
|
|
1158
|
+
"improvements": [
|
|
1159
|
+
{"title": "Model behavior change", "detail": "3-4 sentences describing what the model should do differently", "evidence": "3-4 sentences with specific examples"}
|
|
1160
|
+
]
|
|
1161
|
+
}
|
|
1162
|
+
|
|
1163
1163
|
Include 2-3 improvements based on friction patterns observed.`,
|
|
1164
1164
|
maxTokens: 8192,
|
|
1165
1165
|
},
|
|
@@ -1167,14 +1167,14 @@ Include 2-3 improvements based on friction patterns observed.`,
|
|
|
1167
1167
|
: []),
|
|
1168
1168
|
{
|
|
1169
1169
|
name: 'fun_ending',
|
|
1170
|
-
prompt: `Analyze this Context Code usage data and find a memorable moment.
|
|
1171
|
-
|
|
1172
|
-
RESPOND WITH ONLY A VALID JSON OBJECT:
|
|
1173
|
-
{
|
|
1174
|
-
"headline": "A memorable QUALITATIVE moment from the transcripts - not a statistic. Something human, funny, or surprising.",
|
|
1175
|
-
"detail": "Brief context about when/where this happened"
|
|
1176
|
-
}
|
|
1177
|
-
|
|
1170
|
+
prompt: `Analyze this Context Code usage data and find a memorable moment.
|
|
1171
|
+
|
|
1172
|
+
RESPOND WITH ONLY A VALID JSON OBJECT:
|
|
1173
|
+
{
|
|
1174
|
+
"headline": "A memorable QUALITATIVE moment from the transcripts - not a statistic. Something human, funny, or surprising.",
|
|
1175
|
+
"detail": "Brief context about when/where this happened"
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1178
1178
|
Find something genuinely interesting or amusing from the session summaries.`,
|
|
1179
1179
|
maxTokens: 8192,
|
|
1180
1180
|
},
|
|
@@ -1287,47 +1287,47 @@ async function generateParallelInsights(data, facets) {
|
|
|
1287
1287
|
?.map(o => `- ${o.title}: ${o.whats_possible}`)
|
|
1288
1288
|
.join('\n') || '';
|
|
1289
1289
|
// Now generate "At a Glance" with access to other sections' outputs
|
|
1290
|
-
const atAGlancePrompt = `You're writing an "At a Glance" summary for a Context Code usage insights report for Context Code users. The goal is to help them understand their usage and improve how they can use Claude better, especially as models improve.
|
|
1291
|
-
|
|
1292
|
-
Use this 4-part structure:
|
|
1293
|
-
|
|
1294
|
-
1. **What's working** - What is the user's unique style of interacting with Claude and what are some impactful things they've done? You can include one or two details, but keep it high level since things might not be fresh in the user's memory. Don't be fluffy or overly complimentary. Also, don't focus on the tool calls they use.
|
|
1295
|
-
|
|
1296
|
-
2. **What's hindering you** - Split into (a) Claude's fault (misunderstandings, wrong approaches, bugs) and (b) user-side friction (not providing enough context, environment issues -- ideally more general than just one project). Be honest but constructive.
|
|
1297
|
-
|
|
1298
|
-
3. **Quick wins to try** - Specific Context Code features they could try from the examples below, or a workflow technique if you think it's really compelling. (Avoid stuff like "Ask Claude to confirm before taking actions" or "Type out more context up front" which are less compelling.)
|
|
1299
|
-
|
|
1300
|
-
4. **Ambitious workflows for better models** - As we move to much more capable models over the next 3-6 months, what should they prepare for? What workflows that seem impossible now will become possible? Draw from the appropriate section below.
|
|
1301
|
-
|
|
1302
|
-
Keep each section to 2-3 not-too-long sentences. Don't overwhelm the user. Don't mention specific numerical stats or underlined_categories from the session data below. Use a coaching tone.
|
|
1303
|
-
|
|
1304
|
-
RESPOND WITH ONLY A VALID JSON OBJECT:
|
|
1305
|
-
{
|
|
1306
|
-
"whats_working": "(refer to instructions above)",
|
|
1307
|
-
"whats_hindering": "(refer to instructions above)",
|
|
1308
|
-
"quick_wins": "(refer to instructions above)",
|
|
1309
|
-
"ambitious_workflows": "(refer to instructions above)"
|
|
1310
|
-
}
|
|
1311
|
-
|
|
1312
|
-
SESSION DATA:
|
|
1313
|
-
${fullContext}
|
|
1314
|
-
|
|
1315
|
-
## Project Areas (what user works on)
|
|
1316
|
-
${projectAreasText}
|
|
1317
|
-
|
|
1318
|
-
## Big Wins (impressive accomplishments)
|
|
1319
|
-
${bigWinsText}
|
|
1320
|
-
|
|
1321
|
-
## Friction Categories (where things go wrong)
|
|
1322
|
-
${frictionText}
|
|
1323
|
-
|
|
1324
|
-
## Features to Try
|
|
1325
|
-
${featuresText}
|
|
1326
|
-
|
|
1327
|
-
## Usage Patterns to Adopt
|
|
1328
|
-
${patternsText}
|
|
1329
|
-
|
|
1330
|
-
## On the Horizon (ambitious workflows for better models)
|
|
1290
|
+
const atAGlancePrompt = `You're writing an "At a Glance" summary for a Context Code usage insights report for Context Code users. The goal is to help them understand their usage and improve how they can use Claude better, especially as models improve.
|
|
1291
|
+
|
|
1292
|
+
Use this 4-part structure:
|
|
1293
|
+
|
|
1294
|
+
1. **What's working** - What is the user's unique style of interacting with Claude and what are some impactful things they've done? You can include one or two details, but keep it high level since things might not be fresh in the user's memory. Don't be fluffy or overly complimentary. Also, don't focus on the tool calls they use.
|
|
1295
|
+
|
|
1296
|
+
2. **What's hindering you** - Split into (a) Claude's fault (misunderstandings, wrong approaches, bugs) and (b) user-side friction (not providing enough context, environment issues -- ideally more general than just one project). Be honest but constructive.
|
|
1297
|
+
|
|
1298
|
+
3. **Quick wins to try** - Specific Context Code features they could try from the examples below, or a workflow technique if you think it's really compelling. (Avoid stuff like "Ask Claude to confirm before taking actions" or "Type out more context up front" which are less compelling.)
|
|
1299
|
+
|
|
1300
|
+
4. **Ambitious workflows for better models** - As we move to much more capable models over the next 3-6 months, what should they prepare for? What workflows that seem impossible now will become possible? Draw from the appropriate section below.
|
|
1301
|
+
|
|
1302
|
+
Keep each section to 2-3 not-too-long sentences. Don't overwhelm the user. Don't mention specific numerical stats or underlined_categories from the session data below. Use a coaching tone.
|
|
1303
|
+
|
|
1304
|
+
RESPOND WITH ONLY A VALID JSON OBJECT:
|
|
1305
|
+
{
|
|
1306
|
+
"whats_working": "(refer to instructions above)",
|
|
1307
|
+
"whats_hindering": "(refer to instructions above)",
|
|
1308
|
+
"quick_wins": "(refer to instructions above)",
|
|
1309
|
+
"ambitious_workflows": "(refer to instructions above)"
|
|
1310
|
+
}
|
|
1311
|
+
|
|
1312
|
+
SESSION DATA:
|
|
1313
|
+
${fullContext}
|
|
1314
|
+
|
|
1315
|
+
## Project Areas (what user works on)
|
|
1316
|
+
${projectAreasText}
|
|
1317
|
+
|
|
1318
|
+
## Big Wins (impressive accomplishments)
|
|
1319
|
+
${bigWinsText}
|
|
1320
|
+
|
|
1321
|
+
## Friction Categories (where things go wrong)
|
|
1322
|
+
${frictionText}
|
|
1323
|
+
|
|
1324
|
+
## Features to Try
|
|
1325
|
+
${featuresText}
|
|
1326
|
+
|
|
1327
|
+
## Usage Patterns to Adopt
|
|
1328
|
+
${patternsText}
|
|
1329
|
+
|
|
1330
|
+
## On the Horizon (ambitious workflows for better models)
|
|
1331
1331
|
${horizonText}`;
|
|
1332
1332
|
const atAGlanceSection = {
|
|
1333
1333
|
name: 'at_a_glance',
|
|
@@ -1384,10 +1384,10 @@ function generateBarChart(data, color, maxItems = 6, fixedOrder) {
|
|
|
1384
1384
|
// Use LABEL_MAP if available, otherwise clean up underscores and title case
|
|
1385
1385
|
const cleanLabel = LABEL_MAP[label] ||
|
|
1386
1386
|
label.replace(/_/g, ' ').replace(/\b\w/g, c => c.toUpperCase());
|
|
1387
|
-
return `<div class="bar-row">
|
|
1388
|
-
<div class="bar-label">${escapeHtml(cleanLabel)}</div>
|
|
1389
|
-
<div class="bar-track"><div class="bar-fill" style="width:${pct}%;background:${color}"></div></div>
|
|
1390
|
-
<div class="bar-value">${count}</div>
|
|
1387
|
+
return `<div class="bar-row">
|
|
1388
|
+
<div class="bar-label">${escapeHtml(cleanLabel)}</div>
|
|
1389
|
+
<div class="bar-track"><div class="bar-fill" style="width:${pct}%;background:${color}"></div></div>
|
|
1390
|
+
<div class="bar-value">${count}</div>
|
|
1391
1391
|
</div>`;
|
|
1392
1392
|
})
|
|
1393
1393
|
.join('\n');
|
|
@@ -1427,10 +1427,10 @@ function generateResponseTimeHistogram(times) {
|
|
|
1427
1427
|
return Object.entries(buckets)
|
|
1428
1428
|
.map(([label, count]) => {
|
|
1429
1429
|
const pct = (count / maxVal) * 100;
|
|
1430
|
-
return `<div class="bar-row">
|
|
1431
|
-
<div class="bar-label">${label}</div>
|
|
1432
|
-
<div class="bar-track"><div class="bar-fill" style="width:${pct}%;background:#6366f1"></div></div>
|
|
1433
|
-
<div class="bar-value">${count}</div>
|
|
1430
|
+
return `<div class="bar-row">
|
|
1431
|
+
<div class="bar-label">${label}</div>
|
|
1432
|
+
<div class="bar-track"><div class="bar-fill" style="width:${pct}%;background:#6366f1"></div></div>
|
|
1433
|
+
<div class="bar-value">${count}</div>
|
|
1434
1434
|
</div>`;
|
|
1435
1435
|
})
|
|
1436
1436
|
.join('\n');
|
|
@@ -1455,11 +1455,11 @@ function generateTimeOfDayChart(messageHours) {
|
|
|
1455
1455
|
}));
|
|
1456
1456
|
const maxVal = Math.max(...periodCounts.map(p => p.count)) || 1;
|
|
1457
1457
|
const barsHtml = periodCounts
|
|
1458
|
-
.map(p => `
|
|
1459
|
-
<div class="bar-row">
|
|
1460
|
-
<div class="bar-label">${p.label}</div>
|
|
1461
|
-
<div class="bar-track"><div class="bar-fill" style="width:${(p.count / maxVal) * 100}%;background:#8b5cf6"></div></div>
|
|
1462
|
-
<div class="bar-value">${p.count}</div>
|
|
1458
|
+
.map(p => `
|
|
1459
|
+
<div class="bar-row">
|
|
1460
|
+
<div class="bar-label">${p.label}</div>
|
|
1461
|
+
<div class="bar-track"><div class="bar-fill" style="width:${(p.count / maxVal) * 100}%;background:#8b5cf6"></div></div>
|
|
1462
|
+
<div class="bar-value">${p.count}</div>
|
|
1463
1463
|
</div>`)
|
|
1464
1464
|
.join('\n');
|
|
1465
1465
|
return `<div id="hour-histogram">${barsHtml}</div>`;
|
|
@@ -1489,191 +1489,191 @@ function generateHtmlReport(data, insights) {
|
|
|
1489
1489
|
// Build At a Glance section (new 4-part format with links to sections)
|
|
1490
1490
|
const atAGlance = insights.at_a_glance;
|
|
1491
1491
|
const atAGlanceHtml = atAGlance
|
|
1492
|
-
? `
|
|
1493
|
-
<div class="at-a-glance">
|
|
1494
|
-
<div class="glance-title">At a Glance</div>
|
|
1495
|
-
<div class="glance-sections">
|
|
1496
|
-
${atAGlance.whats_working ? `<div class="glance-section"><strong>What's working:</strong> ${escapeHtmlWithBold(atAGlance.whats_working)} <a href="#section-wins" class="see-more">Impressive Things You Did →</a></div>` : ''}
|
|
1497
|
-
${atAGlance.whats_hindering ? `<div class="glance-section"><strong>What's hindering you:</strong> ${escapeHtmlWithBold(atAGlance.whats_hindering)} <a href="#section-friction" class="see-more">Where Things Go Wrong →</a></div>` : ''}
|
|
1498
|
-
${atAGlance.quick_wins ? `<div class="glance-section"><strong>Quick wins to try:</strong> ${escapeHtmlWithBold(atAGlance.quick_wins)} <a href="#section-features" class="see-more">Features to Try →</a></div>` : ''}
|
|
1499
|
-
${atAGlance.ambitious_workflows ? `<div class="glance-section"><strong>Ambitious workflows:</strong> ${escapeHtmlWithBold(atAGlance.ambitious_workflows)} <a href="#section-horizon" class="see-more">On the Horizon →</a></div>` : ''}
|
|
1500
|
-
</div>
|
|
1501
|
-
</div>
|
|
1492
|
+
? `
|
|
1493
|
+
<div class="at-a-glance">
|
|
1494
|
+
<div class="glance-title">At a Glance</div>
|
|
1495
|
+
<div class="glance-sections">
|
|
1496
|
+
${atAGlance.whats_working ? `<div class="glance-section"><strong>What's working:</strong> ${escapeHtmlWithBold(atAGlance.whats_working)} <a href="#section-wins" class="see-more">Impressive Things You Did →</a></div>` : ''}
|
|
1497
|
+
${atAGlance.whats_hindering ? `<div class="glance-section"><strong>What's hindering you:</strong> ${escapeHtmlWithBold(atAGlance.whats_hindering)} <a href="#section-friction" class="see-more">Where Things Go Wrong →</a></div>` : ''}
|
|
1498
|
+
${atAGlance.quick_wins ? `<div class="glance-section"><strong>Quick wins to try:</strong> ${escapeHtmlWithBold(atAGlance.quick_wins)} <a href="#section-features" class="see-more">Features to Try →</a></div>` : ''}
|
|
1499
|
+
${atAGlance.ambitious_workflows ? `<div class="glance-section"><strong>Ambitious workflows:</strong> ${escapeHtmlWithBold(atAGlance.ambitious_workflows)} <a href="#section-horizon" class="see-more">On the Horizon →</a></div>` : ''}
|
|
1500
|
+
</div>
|
|
1501
|
+
</div>
|
|
1502
1502
|
`
|
|
1503
1503
|
: '';
|
|
1504
1504
|
// Build project areas section
|
|
1505
1505
|
const projectAreas = insights.project_areas?.areas || [];
|
|
1506
1506
|
const projectAreasHtml = projectAreas.length > 0
|
|
1507
|
-
? `
|
|
1508
|
-
<h2 id="section-work">What You Work On</h2>
|
|
1509
|
-
<div class="project-areas">
|
|
1507
|
+
? `
|
|
1508
|
+
<h2 id="section-work">What You Work On</h2>
|
|
1509
|
+
<div class="project-areas">
|
|
1510
1510
|
${projectAreas
|
|
1511
|
-
.map(area => `
|
|
1512
|
-
<div class="project-area">
|
|
1513
|
-
<div class="area-header">
|
|
1514
|
-
<span class="area-name">${escapeHtml(area.name)}</span>
|
|
1515
|
-
<span class="area-count">~${area.session_count} sessions</span>
|
|
1516
|
-
</div>
|
|
1517
|
-
<div class="area-desc">${escapeHtml(area.description)}</div>
|
|
1518
|
-
</div>
|
|
1511
|
+
.map(area => `
|
|
1512
|
+
<div class="project-area">
|
|
1513
|
+
<div class="area-header">
|
|
1514
|
+
<span class="area-name">${escapeHtml(area.name)}</span>
|
|
1515
|
+
<span class="area-count">~${area.session_count} sessions</span>
|
|
1516
|
+
</div>
|
|
1517
|
+
<div class="area-desc">${escapeHtml(area.description)}</div>
|
|
1518
|
+
</div>
|
|
1519
1519
|
`)
|
|
1520
|
-
.join('')}
|
|
1521
|
-
</div>
|
|
1520
|
+
.join('')}
|
|
1521
|
+
</div>
|
|
1522
1522
|
`
|
|
1523
1523
|
: '';
|
|
1524
1524
|
// Build interaction style section
|
|
1525
1525
|
const interactionStyle = insights.interaction_style;
|
|
1526
1526
|
const interactionHtml = interactionStyle?.narrative
|
|
1527
|
-
? `
|
|
1528
|
-
<h2 id="section-usage">How You Use Context Code</h2>
|
|
1529
|
-
<div class="narrative">
|
|
1530
|
-
${markdownToHtml(interactionStyle.narrative)}
|
|
1531
|
-
${interactionStyle.key_pattern ? `<div class="key-insight"><strong>Key pattern:</strong> ${escapeHtml(interactionStyle.key_pattern)}</div>` : ''}
|
|
1532
|
-
</div>
|
|
1527
|
+
? `
|
|
1528
|
+
<h2 id="section-usage">How You Use Context Code</h2>
|
|
1529
|
+
<div class="narrative">
|
|
1530
|
+
${markdownToHtml(interactionStyle.narrative)}
|
|
1531
|
+
${interactionStyle.key_pattern ? `<div class="key-insight"><strong>Key pattern:</strong> ${escapeHtml(interactionStyle.key_pattern)}</div>` : ''}
|
|
1532
|
+
</div>
|
|
1533
1533
|
`
|
|
1534
1534
|
: '';
|
|
1535
1535
|
// Build what works section
|
|
1536
1536
|
const whatWorks = insights.what_works;
|
|
1537
1537
|
const whatWorksHtml = whatWorks?.impressive_workflows && whatWorks.impressive_workflows.length > 0
|
|
1538
|
-
? `
|
|
1539
|
-
<h2 id="section-wins">Impressive Things You Did</h2>
|
|
1540
|
-
${whatWorks.intro ? `<p class="section-intro">${escapeHtml(whatWorks.intro)}</p>` : ''}
|
|
1541
|
-
<div class="big-wins">
|
|
1538
|
+
? `
|
|
1539
|
+
<h2 id="section-wins">Impressive Things You Did</h2>
|
|
1540
|
+
${whatWorks.intro ? `<p class="section-intro">${escapeHtml(whatWorks.intro)}</p>` : ''}
|
|
1541
|
+
<div class="big-wins">
|
|
1542
1542
|
${whatWorks.impressive_workflows
|
|
1543
|
-
.map(wf => `
|
|
1544
|
-
<div class="big-win">
|
|
1545
|
-
<div class="big-win-title">${escapeHtml(wf.title || '')}</div>
|
|
1546
|
-
<div class="big-win-desc">${escapeHtml(wf.description || '')}</div>
|
|
1547
|
-
</div>
|
|
1543
|
+
.map(wf => `
|
|
1544
|
+
<div class="big-win">
|
|
1545
|
+
<div class="big-win-title">${escapeHtml(wf.title || '')}</div>
|
|
1546
|
+
<div class="big-win-desc">${escapeHtml(wf.description || '')}</div>
|
|
1547
|
+
</div>
|
|
1548
1548
|
`)
|
|
1549
|
-
.join('')}
|
|
1550
|
-
</div>
|
|
1549
|
+
.join('')}
|
|
1550
|
+
</div>
|
|
1551
1551
|
`
|
|
1552
1552
|
: '';
|
|
1553
1553
|
// Build friction section
|
|
1554
1554
|
const frictionAnalysis = insights.friction_analysis;
|
|
1555
1555
|
const frictionHtml = frictionAnalysis?.categories && frictionAnalysis.categories.length > 0
|
|
1556
|
-
? `
|
|
1557
|
-
<h2 id="section-friction">Where Things Go Wrong</h2>
|
|
1558
|
-
${frictionAnalysis.intro ? `<p class="section-intro">${escapeHtml(frictionAnalysis.intro)}</p>` : ''}
|
|
1559
|
-
<div class="friction-categories">
|
|
1556
|
+
? `
|
|
1557
|
+
<h2 id="section-friction">Where Things Go Wrong</h2>
|
|
1558
|
+
${frictionAnalysis.intro ? `<p class="section-intro">${escapeHtml(frictionAnalysis.intro)}</p>` : ''}
|
|
1559
|
+
<div class="friction-categories">
|
|
1560
1560
|
${frictionAnalysis.categories
|
|
1561
|
-
.map(cat => `
|
|
1562
|
-
<div class="friction-category">
|
|
1563
|
-
<div class="friction-title">${escapeHtml(cat.category || '')}</div>
|
|
1564
|
-
<div class="friction-desc">${escapeHtml(cat.description || '')}</div>
|
|
1565
|
-
${cat.examples ? `<ul class="friction-examples">${cat.examples.map(ex => `<li>${escapeHtml(ex)}</li>`).join('')}</ul>` : ''}
|
|
1566
|
-
</div>
|
|
1561
|
+
.map(cat => `
|
|
1562
|
+
<div class="friction-category">
|
|
1563
|
+
<div class="friction-title">${escapeHtml(cat.category || '')}</div>
|
|
1564
|
+
<div class="friction-desc">${escapeHtml(cat.description || '')}</div>
|
|
1565
|
+
${cat.examples ? `<ul class="friction-examples">${cat.examples.map(ex => `<li>${escapeHtml(ex)}</li>`).join('')}</ul>` : ''}
|
|
1566
|
+
</div>
|
|
1567
1567
|
`)
|
|
1568
|
-
.join('')}
|
|
1569
|
-
</div>
|
|
1568
|
+
.join('')}
|
|
1569
|
+
</div>
|
|
1570
1570
|
`
|
|
1571
1571
|
: '';
|
|
1572
1572
|
// Build suggestions section
|
|
1573
1573
|
const suggestions = insights.suggestions;
|
|
1574
1574
|
const suggestionsHtml = suggestions
|
|
1575
|
-
? `
|
|
1575
|
+
? `
|
|
1576
1576
|
${suggestions.claude_md_additions &&
|
|
1577
1577
|
suggestions.claude_md_additions.length > 0
|
|
1578
|
-
? `
|
|
1579
|
-
<h2 id="section-features">Existing CC Features to Try</h2>
|
|
1580
|
-
<div class="claude-md-section">
|
|
1581
|
-
<h3>Suggested CLAUDE.md Additions</h3>
|
|
1582
|
-
<p style="font-size: 12px; color: #64748b; margin-bottom: 12px;">Just copy this into Context Code to add it to your CLAUDE.md.</p>
|
|
1583
|
-
<div class="claude-md-actions">
|
|
1584
|
-
<button class="copy-all-btn" onclick="copyAllCheckedClaudeMd()">Copy All Checked</button>
|
|
1585
|
-
</div>
|
|
1578
|
+
? `
|
|
1579
|
+
<h2 id="section-features">Existing CC Features to Try</h2>
|
|
1580
|
+
<div class="claude-md-section">
|
|
1581
|
+
<h3>Suggested CLAUDE.md Additions</h3>
|
|
1582
|
+
<p style="font-size: 12px; color: #64748b; margin-bottom: 12px;">Just copy this into Context Code to add it to your CLAUDE.md.</p>
|
|
1583
|
+
<div class="claude-md-actions">
|
|
1584
|
+
<button class="copy-all-btn" onclick="copyAllCheckedClaudeMd()">Copy All Checked</button>
|
|
1585
|
+
</div>
|
|
1586
1586
|
${suggestions.claude_md_additions
|
|
1587
|
-
.map((add, i) => `
|
|
1588
|
-
<div class="claude-md-item">
|
|
1589
|
-
<input type="checkbox" id="cmd-${i}" class="cmd-checkbox" checked data-text="${escapeHtml(add.prompt_scaffold || add.where || 'Add to CLAUDE.md')}\\n\\n${escapeHtml(add.addition)}">
|
|
1590
|
-
<label for="cmd-${i}">
|
|
1591
|
-
<code class="cmd-code">${escapeHtml(add.addition)}</code>
|
|
1592
|
-
<button class="copy-btn" onclick="copyCmdItem(${i})">Copy</button>
|
|
1593
|
-
</label>
|
|
1594
|
-
<div class="cmd-why">${escapeHtml(add.why)}</div>
|
|
1595
|
-
</div>
|
|
1587
|
+
.map((add, i) => `
|
|
1588
|
+
<div class="claude-md-item">
|
|
1589
|
+
<input type="checkbox" id="cmd-${i}" class="cmd-checkbox" checked data-text="${escapeHtml(add.prompt_scaffold || add.where || 'Add to CLAUDE.md')}\\n\\n${escapeHtml(add.addition)}">
|
|
1590
|
+
<label for="cmd-${i}">
|
|
1591
|
+
<code class="cmd-code">${escapeHtml(add.addition)}</code>
|
|
1592
|
+
<button class="copy-btn" onclick="copyCmdItem(${i})">Copy</button>
|
|
1593
|
+
</label>
|
|
1594
|
+
<div class="cmd-why">${escapeHtml(add.why)}</div>
|
|
1595
|
+
</div>
|
|
1596
1596
|
`)
|
|
1597
|
-
.join('')}
|
|
1598
|
-
</div>
|
|
1597
|
+
.join('')}
|
|
1598
|
+
</div>
|
|
1599
1599
|
`
|
|
1600
|
-
: ''}
|
|
1600
|
+
: ''}
|
|
1601
1601
|
${suggestions.features_to_try && suggestions.features_to_try.length > 0
|
|
1602
|
-
? `
|
|
1603
|
-
<p style="font-size: 13px; color: #64748b; margin-bottom: 12px;">Just copy this into Context Code and it'll set it up for you.</p>
|
|
1604
|
-
<div class="features-section">
|
|
1602
|
+
? `
|
|
1603
|
+
<p style="font-size: 13px; color: #64748b; margin-bottom: 12px;">Just copy this into Context Code and it'll set it up for you.</p>
|
|
1604
|
+
<div class="features-section">
|
|
1605
1605
|
${suggestions.features_to_try
|
|
1606
|
-
.map(feat => `
|
|
1607
|
-
<div class="feature-card">
|
|
1608
|
-
<div class="feature-title">${escapeHtml(feat.feature || '')}</div>
|
|
1609
|
-
<div class="feature-oneliner">${escapeHtml(feat.one_liner || '')}</div>
|
|
1610
|
-
<div class="feature-why"><strong>Why for you:</strong> ${escapeHtml(feat.why_for_you || '')}</div>
|
|
1606
|
+
.map(feat => `
|
|
1607
|
+
<div class="feature-card">
|
|
1608
|
+
<div class="feature-title">${escapeHtml(feat.feature || '')}</div>
|
|
1609
|
+
<div class="feature-oneliner">${escapeHtml(feat.one_liner || '')}</div>
|
|
1610
|
+
<div class="feature-why"><strong>Why for you:</strong> ${escapeHtml(feat.why_for_you || '')}</div>
|
|
1611
1611
|
${feat.example_code
|
|
1612
|
-
? `
|
|
1613
|
-
<div class="feature-examples">
|
|
1614
|
-
<div class="feature-example">
|
|
1615
|
-
<div class="example-code-row">
|
|
1616
|
-
<code class="example-code">${escapeHtml(feat.example_code)}</code>
|
|
1617
|
-
<button class="copy-btn" onclick="copyText(this)">Copy</button>
|
|
1618
|
-
</div>
|
|
1619
|
-
</div>
|
|
1620
|
-
</div>
|
|
1612
|
+
? `
|
|
1613
|
+
<div class="feature-examples">
|
|
1614
|
+
<div class="feature-example">
|
|
1615
|
+
<div class="example-code-row">
|
|
1616
|
+
<code class="example-code">${escapeHtml(feat.example_code)}</code>
|
|
1617
|
+
<button class="copy-btn" onclick="copyText(this)">Copy</button>
|
|
1618
|
+
</div>
|
|
1619
|
+
</div>
|
|
1620
|
+
</div>
|
|
1621
1621
|
`
|
|
1622
|
-
: ''}
|
|
1623
|
-
</div>
|
|
1622
|
+
: ''}
|
|
1623
|
+
</div>
|
|
1624
1624
|
`)
|
|
1625
|
-
.join('')}
|
|
1626
|
-
</div>
|
|
1625
|
+
.join('')}
|
|
1626
|
+
</div>
|
|
1627
1627
|
`
|
|
1628
|
-
: ''}
|
|
1628
|
+
: ''}
|
|
1629
1629
|
${suggestions.usage_patterns && suggestions.usage_patterns.length > 0
|
|
1630
|
-
? `
|
|
1631
|
-
<h2 id="section-patterns">New Ways to Use Context Code</h2>
|
|
1632
|
-
<p style="font-size: 13px; color: #64748b; margin-bottom: 12px;">Just copy this into Context Code and it'll walk you through it.</p>
|
|
1633
|
-
<div class="patterns-section">
|
|
1630
|
+
? `
|
|
1631
|
+
<h2 id="section-patterns">New Ways to Use Context Code</h2>
|
|
1632
|
+
<p style="font-size: 13px; color: #64748b; margin-bottom: 12px;">Just copy this into Context Code and it'll walk you through it.</p>
|
|
1633
|
+
<div class="patterns-section">
|
|
1634
1634
|
${suggestions.usage_patterns
|
|
1635
|
-
.map(pat => `
|
|
1636
|
-
<div class="pattern-card">
|
|
1637
|
-
<div class="pattern-title">${escapeHtml(pat.title || '')}</div>
|
|
1638
|
-
<div class="pattern-summary">${escapeHtml(pat.suggestion || '')}</div>
|
|
1639
|
-
${pat.detail ? `<div class="pattern-detail">${escapeHtml(pat.detail)}</div>` : ''}
|
|
1635
|
+
.map(pat => `
|
|
1636
|
+
<div class="pattern-card">
|
|
1637
|
+
<div class="pattern-title">${escapeHtml(pat.title || '')}</div>
|
|
1638
|
+
<div class="pattern-summary">${escapeHtml(pat.suggestion || '')}</div>
|
|
1639
|
+
${pat.detail ? `<div class="pattern-detail">${escapeHtml(pat.detail)}</div>` : ''}
|
|
1640
1640
|
${pat.copyable_prompt
|
|
1641
|
-
? `
|
|
1642
|
-
<div class="copyable-prompt-section">
|
|
1643
|
-
<div class="prompt-label">Paste into Context Code:</div>
|
|
1644
|
-
<div class="copyable-prompt-row">
|
|
1645
|
-
<code class="copyable-prompt">${escapeHtml(pat.copyable_prompt)}</code>
|
|
1646
|
-
<button class="copy-btn" onclick="copyText(this)">Copy</button>
|
|
1647
|
-
</div>
|
|
1648
|
-
</div>
|
|
1641
|
+
? `
|
|
1642
|
+
<div class="copyable-prompt-section">
|
|
1643
|
+
<div class="prompt-label">Paste into Context Code:</div>
|
|
1644
|
+
<div class="copyable-prompt-row">
|
|
1645
|
+
<code class="copyable-prompt">${escapeHtml(pat.copyable_prompt)}</code>
|
|
1646
|
+
<button class="copy-btn" onclick="copyText(this)">Copy</button>
|
|
1647
|
+
</div>
|
|
1648
|
+
</div>
|
|
1649
1649
|
`
|
|
1650
|
-
: ''}
|
|
1651
|
-
</div>
|
|
1650
|
+
: ''}
|
|
1651
|
+
</div>
|
|
1652
1652
|
`)
|
|
1653
|
-
.join('')}
|
|
1654
|
-
</div>
|
|
1653
|
+
.join('')}
|
|
1654
|
+
</div>
|
|
1655
1655
|
`
|
|
1656
|
-
: ''}
|
|
1656
|
+
: ''}
|
|
1657
1657
|
`
|
|
1658
1658
|
: '';
|
|
1659
1659
|
// Build On the Horizon section
|
|
1660
1660
|
const horizonData = insights.on_the_horizon;
|
|
1661
1661
|
const horizonHtml = horizonData?.opportunities && horizonData.opportunities.length > 0
|
|
1662
|
-
? `
|
|
1663
|
-
<h2 id="section-horizon">On the Horizon</h2>
|
|
1664
|
-
${horizonData.intro ? `<p class="section-intro">${escapeHtml(horizonData.intro)}</p>` : ''}
|
|
1665
|
-
<div class="horizon-section">
|
|
1662
|
+
? `
|
|
1663
|
+
<h2 id="section-horizon">On the Horizon</h2>
|
|
1664
|
+
${horizonData.intro ? `<p class="section-intro">${escapeHtml(horizonData.intro)}</p>` : ''}
|
|
1665
|
+
<div class="horizon-section">
|
|
1666
1666
|
${horizonData.opportunities
|
|
1667
|
-
.map(opp => `
|
|
1668
|
-
<div class="horizon-card">
|
|
1669
|
-
<div class="horizon-title">${escapeHtml(opp.title || '')}</div>
|
|
1670
|
-
<div class="horizon-possible">${escapeHtml(opp.whats_possible || '')}</div>
|
|
1671
|
-
${opp.how_to_try ? `<div class="horizon-tip"><strong>Getting started:</strong> ${escapeHtml(opp.how_to_try)}</div>` : ''}
|
|
1672
|
-
${opp.copyable_prompt ? `<div class="pattern-prompt"><div class="prompt-label">Paste into Context Code:</div><code>${escapeHtml(opp.copyable_prompt)}</code><button class="copy-btn" onclick="copyText(this)">Copy</button></div>` : ''}
|
|
1673
|
-
</div>
|
|
1667
|
+
.map(opp => `
|
|
1668
|
+
<div class="horizon-card">
|
|
1669
|
+
<div class="horizon-title">${escapeHtml(opp.title || '')}</div>
|
|
1670
|
+
<div class="horizon-possible">${escapeHtml(opp.whats_possible || '')}</div>
|
|
1671
|
+
${opp.how_to_try ? `<div class="horizon-tip"><strong>Getting started:</strong> ${escapeHtml(opp.how_to_try)}</div>` : ''}
|
|
1672
|
+
${opp.copyable_prompt ? `<div class="pattern-prompt"><div class="prompt-label">Paste into Context Code:</div><code>${escapeHtml(opp.copyable_prompt)}</code><button class="copy-btn" onclick="copyText(this)">Copy</button></div>` : ''}
|
|
1673
|
+
</div>
|
|
1674
1674
|
`)
|
|
1675
|
-
.join('')}
|
|
1676
|
-
</div>
|
|
1675
|
+
.join('')}
|
|
1676
|
+
</div>
|
|
1677
1677
|
`
|
|
1678
1678
|
: '';
|
|
1679
1679
|
// Build Team Feedback section (collapsible, ant-only)
|
|
@@ -1684,435 +1684,435 @@ function generateHtmlReport(data, insights) {
|
|
|
1684
1684
|
? insights.model_behavior_improvements?.improvements || []
|
|
1685
1685
|
: [];
|
|
1686
1686
|
const teamFeedbackHtml = ccImprovements.length > 0 || modelImprovements.length > 0
|
|
1687
|
-
? `
|
|
1688
|
-
<h2 id="section-feedback" class="feedback-header">Closing the Loop: Feedback for Other Teams</h2>
|
|
1689
|
-
<p class="feedback-intro">Suggestions for the CC product and model teams based on your usage patterns. Click to expand.</p>
|
|
1687
|
+
? `
|
|
1688
|
+
<h2 id="section-feedback" class="feedback-header">Closing the Loop: Feedback for Other Teams</h2>
|
|
1689
|
+
<p class="feedback-intro">Suggestions for the CC product and model teams based on your usage patterns. Click to expand.</p>
|
|
1690
1690
|
${ccImprovements.length > 0
|
|
1691
|
-
? `
|
|
1692
|
-
<div class="collapsible-section">
|
|
1693
|
-
<div class="collapsible-header" onclick="toggleCollapsible(this)">
|
|
1694
|
-
<span class="collapsible-arrow">▶</span>
|
|
1695
|
-
<h3>Product Improvements for CC Team</h3>
|
|
1696
|
-
</div>
|
|
1697
|
-
<div class="collapsible-content">
|
|
1698
|
-
<div class="suggestions-section">
|
|
1691
|
+
? `
|
|
1692
|
+
<div class="collapsible-section">
|
|
1693
|
+
<div class="collapsible-header" onclick="toggleCollapsible(this)">
|
|
1694
|
+
<span class="collapsible-arrow">▶</span>
|
|
1695
|
+
<h3>Product Improvements for CC Team</h3>
|
|
1696
|
+
</div>
|
|
1697
|
+
<div class="collapsible-content">
|
|
1698
|
+
<div class="suggestions-section">
|
|
1699
1699
|
${ccImprovements
|
|
1700
|
-
.map(imp => `
|
|
1701
|
-
<div class="feedback-card team-card">
|
|
1702
|
-
<div class="feedback-title">${escapeHtml(imp.title || '')}</div>
|
|
1703
|
-
<div class="feedback-detail">${escapeHtml(imp.detail || '')}</div>
|
|
1704
|
-
${imp.evidence ? `<div class="feedback-evidence"><em>Evidence:</em> ${escapeHtml(imp.evidence)}</div>` : ''}
|
|
1705
|
-
</div>
|
|
1700
|
+
.map(imp => `
|
|
1701
|
+
<div class="feedback-card team-card">
|
|
1702
|
+
<div class="feedback-title">${escapeHtml(imp.title || '')}</div>
|
|
1703
|
+
<div class="feedback-detail">${escapeHtml(imp.detail || '')}</div>
|
|
1704
|
+
${imp.evidence ? `<div class="feedback-evidence"><em>Evidence:</em> ${escapeHtml(imp.evidence)}</div>` : ''}
|
|
1705
|
+
</div>
|
|
1706
1706
|
`)
|
|
1707
|
-
.join('')}
|
|
1708
|
-
</div>
|
|
1709
|
-
</div>
|
|
1710
|
-
</div>
|
|
1707
|
+
.join('')}
|
|
1708
|
+
</div>
|
|
1709
|
+
</div>
|
|
1710
|
+
</div>
|
|
1711
1711
|
`
|
|
1712
|
-
: ''}
|
|
1712
|
+
: ''}
|
|
1713
1713
|
${modelImprovements.length > 0
|
|
1714
|
-
? `
|
|
1715
|
-
<div class="collapsible-section">
|
|
1716
|
-
<div class="collapsible-header" onclick="toggleCollapsible(this)">
|
|
1717
|
-
<span class="collapsible-arrow">▶</span>
|
|
1718
|
-
<h3>Model Behavior Improvements</h3>
|
|
1719
|
-
</div>
|
|
1720
|
-
<div class="collapsible-content">
|
|
1721
|
-
<div class="suggestions-section">
|
|
1714
|
+
? `
|
|
1715
|
+
<div class="collapsible-section">
|
|
1716
|
+
<div class="collapsible-header" onclick="toggleCollapsible(this)">
|
|
1717
|
+
<span class="collapsible-arrow">▶</span>
|
|
1718
|
+
<h3>Model Behavior Improvements</h3>
|
|
1719
|
+
</div>
|
|
1720
|
+
<div class="collapsible-content">
|
|
1721
|
+
<div class="suggestions-section">
|
|
1722
1722
|
${modelImprovements
|
|
1723
|
-
.map(imp => `
|
|
1724
|
-
<div class="feedback-card model-card">
|
|
1725
|
-
<div class="feedback-title">${escapeHtml(imp.title || '')}</div>
|
|
1726
|
-
<div class="feedback-detail">${escapeHtml(imp.detail || '')}</div>
|
|
1727
|
-
${imp.evidence ? `<div class="feedback-evidence"><em>Evidence:</em> ${escapeHtml(imp.evidence)}</div>` : ''}
|
|
1728
|
-
</div>
|
|
1723
|
+
.map(imp => `
|
|
1724
|
+
<div class="feedback-card model-card">
|
|
1725
|
+
<div class="feedback-title">${escapeHtml(imp.title || '')}</div>
|
|
1726
|
+
<div class="feedback-detail">${escapeHtml(imp.detail || '')}</div>
|
|
1727
|
+
${imp.evidence ? `<div class="feedback-evidence"><em>Evidence:</em> ${escapeHtml(imp.evidence)}</div>` : ''}
|
|
1728
|
+
</div>
|
|
1729
1729
|
`)
|
|
1730
|
-
.join('')}
|
|
1731
|
-
</div>
|
|
1732
|
-
</div>
|
|
1733
|
-
</div>
|
|
1730
|
+
.join('')}
|
|
1731
|
+
</div>
|
|
1732
|
+
</div>
|
|
1733
|
+
</div>
|
|
1734
1734
|
`
|
|
1735
|
-
: ''}
|
|
1735
|
+
: ''}
|
|
1736
1736
|
`
|
|
1737
1737
|
: '';
|
|
1738
1738
|
// Build Fun Ending section
|
|
1739
1739
|
const funEnding = insights.fun_ending;
|
|
1740
1740
|
const funEndingHtml = funEnding?.headline
|
|
1741
|
-
? `
|
|
1742
|
-
<div class="fun-ending">
|
|
1743
|
-
<div class="fun-headline">"${escapeHtml(funEnding.headline)}"</div>
|
|
1744
|
-
${funEnding.detail ? `<div class="fun-detail">${escapeHtml(funEnding.detail)}</div>` : ''}
|
|
1745
|
-
</div>
|
|
1741
|
+
? `
|
|
1742
|
+
<div class="fun-ending">
|
|
1743
|
+
<div class="fun-headline">"${escapeHtml(funEnding.headline)}"</div>
|
|
1744
|
+
${funEnding.detail ? `<div class="fun-detail">${escapeHtml(funEnding.detail)}</div>` : ''}
|
|
1745
|
+
</div>
|
|
1746
1746
|
`
|
|
1747
1747
|
: '';
|
|
1748
|
-
const css = `
|
|
1749
|
-
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
1750
|
-
body { font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif; background: #f8fafc; color: #334155; line-height: 1.65; padding: 48px 24px; }
|
|
1751
|
-
.container { max-width: 800px; margin: 0 auto; }
|
|
1752
|
-
h1 { font-size: 32px; font-weight: 700; color: #0f172a; margin-bottom: 8px; }
|
|
1753
|
-
h2 { font-size: 20px; font-weight: 600; color: #0f172a; margin-top: 48px; margin-bottom: 16px; }
|
|
1754
|
-
.subtitle { color: #64748b; font-size: 15px; margin-bottom: 32px; }
|
|
1755
|
-
.nav-toc { display: flex; flex-wrap: wrap; gap: 8px; margin: 24px 0 32px 0; padding: 16px; background: white; border-radius: 8px; border: 1px solid #e2e8f0; }
|
|
1756
|
-
.nav-toc a { font-size: 12px; color: #64748b; text-decoration: none; padding: 6px 12px; border-radius: 6px; background: #f1f5f9; transition: all 0.15s; }
|
|
1757
|
-
.nav-toc a:hover { background: #e2e8f0; color: #334155; }
|
|
1758
|
-
.stats-row { display: flex; gap: 24px; margin-bottom: 40px; padding: 20px 0; border-top: 1px solid #e2e8f0; border-bottom: 1px solid #e2e8f0; flex-wrap: wrap; }
|
|
1759
|
-
.stat { text-align: center; }
|
|
1760
|
-
.stat-value { font-size: 24px; font-weight: 700; color: #0f172a; }
|
|
1761
|
-
.stat-label { font-size: 11px; color: #64748b; text-transform: uppercase; }
|
|
1762
|
-
.at-a-glance { background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%); border: 1px solid #f59e0b; border-radius: 12px; padding: 20px 24px; margin-bottom: 32px; }
|
|
1763
|
-
.glance-title { font-size: 16px; font-weight: 700; color: #92400e; margin-bottom: 16px; }
|
|
1764
|
-
.glance-sections { display: flex; flex-direction: column; gap: 12px; }
|
|
1765
|
-
.glance-section { font-size: 14px; color: #78350f; line-height: 1.6; }
|
|
1766
|
-
.glance-section strong { color: #92400e; }
|
|
1767
|
-
.see-more { color: #b45309; text-decoration: none; font-size: 13px; white-space: nowrap; }
|
|
1768
|
-
.see-more:hover { text-decoration: underline; }
|
|
1769
|
-
.project-areas { display: flex; flex-direction: column; gap: 12px; margin-bottom: 32px; }
|
|
1770
|
-
.project-area { background: white; border: 1px solid #e2e8f0; border-radius: 8px; padding: 16px; }
|
|
1771
|
-
.area-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px; }
|
|
1772
|
-
.area-name { font-weight: 600; font-size: 15px; color: #0f172a; }
|
|
1773
|
-
.area-count { font-size: 12px; color: #64748b; background: #f1f5f9; padding: 2px 8px; border-radius: 4px; }
|
|
1774
|
-
.area-desc { font-size: 14px; color: #475569; line-height: 1.5; }
|
|
1775
|
-
.narrative { background: white; border: 1px solid #e2e8f0; border-radius: 8px; padding: 20px; margin-bottom: 24px; }
|
|
1776
|
-
.narrative p { margin-bottom: 12px; font-size: 14px; color: #475569; line-height: 1.7; }
|
|
1777
|
-
.key-insight { background: #f0fdf4; border: 1px solid #bbf7d0; border-radius: 8px; padding: 12px 16px; margin-top: 12px; font-size: 14px; color: #166534; }
|
|
1778
|
-
.section-intro { font-size: 14px; color: #64748b; margin-bottom: 16px; }
|
|
1779
|
-
.big-wins { display: flex; flex-direction: column; gap: 12px; margin-bottom: 24px; }
|
|
1780
|
-
.big-win { background: #f0fdf4; border: 1px solid #bbf7d0; border-radius: 8px; padding: 16px; }
|
|
1781
|
-
.big-win-title { font-weight: 600; font-size: 15px; color: #166534; margin-bottom: 8px; }
|
|
1782
|
-
.big-win-desc { font-size: 14px; color: #15803d; line-height: 1.5; }
|
|
1783
|
-
.friction-categories { display: flex; flex-direction: column; gap: 16px; margin-bottom: 24px; }
|
|
1784
|
-
.friction-category { background: #fef2f2; border: 1px solid #fca5a5; border-radius: 8px; padding: 16px; }
|
|
1785
|
-
.friction-title { font-weight: 600; font-size: 15px; color: #991b1b; margin-bottom: 6px; }
|
|
1786
|
-
.friction-desc { font-size: 13px; color: #7f1d1d; margin-bottom: 10px; }
|
|
1787
|
-
.friction-examples { margin: 0 0 0 20px; font-size: 13px; color: #334155; }
|
|
1788
|
-
.friction-examples li { margin-bottom: 4px; }
|
|
1789
|
-
.claude-md-section { background: #eff6ff; border: 1px solid #bfdbfe; border-radius: 8px; padding: 16px; margin-bottom: 20px; }
|
|
1790
|
-
.claude-md-section h3 { font-size: 14px; font-weight: 600; color: #1e40af; margin: 0 0 12px 0; }
|
|
1791
|
-
.claude-md-actions { margin-bottom: 12px; padding-bottom: 12px; border-bottom: 1px solid #dbeafe; }
|
|
1792
|
-
.copy-all-btn { background: #2563eb; color: white; border: none; border-radius: 4px; padding: 6px 12px; font-size: 12px; cursor: pointer; font-weight: 500; transition: all 0.2s; }
|
|
1793
|
-
.copy-all-btn:hover { background: #1d4ed8; }
|
|
1794
|
-
.copy-all-btn.copied { background: #16a34a; }
|
|
1795
|
-
.claude-md-item { display: flex; flex-wrap: wrap; align-items: flex-start; gap: 8px; padding: 10px 0; border-bottom: 1px solid #dbeafe; }
|
|
1796
|
-
.claude-md-item:last-child { border-bottom: none; }
|
|
1797
|
-
.cmd-checkbox { margin-top: 2px; }
|
|
1798
|
-
.cmd-code { background: white; padding: 8px 12px; border-radius: 4px; font-size: 12px; color: #1e40af; border: 1px solid #bfdbfe; font-family: monospace; display: block; white-space: pre-wrap; word-break: break-word; flex: 1; }
|
|
1799
|
-
.cmd-why { font-size: 12px; color: #64748b; width: 100%; padding-left: 24px; margin-top: 4px; }
|
|
1800
|
-
.features-section, .patterns-section { display: flex; flex-direction: column; gap: 12px; margin: 16px 0; }
|
|
1801
|
-
.feature-card { background: #f0fdf4; border: 1px solid #86efac; border-radius: 8px; padding: 16px; }
|
|
1802
|
-
.pattern-card { background: #f0f9ff; border: 1px solid #7dd3fc; border-radius: 8px; padding: 16px; }
|
|
1803
|
-
.feature-title, .pattern-title { font-weight: 600; font-size: 15px; color: #0f172a; margin-bottom: 6px; }
|
|
1804
|
-
.feature-oneliner { font-size: 14px; color: #475569; margin-bottom: 8px; }
|
|
1805
|
-
.pattern-summary { font-size: 14px; color: #475569; margin-bottom: 8px; }
|
|
1806
|
-
.feature-why, .pattern-detail { font-size: 13px; color: #334155; line-height: 1.5; }
|
|
1807
|
-
.feature-examples { margin-top: 12px; }
|
|
1808
|
-
.feature-example { padding: 8px 0; border-top: 1px solid #d1fae5; }
|
|
1809
|
-
.feature-example:first-child { border-top: none; }
|
|
1810
|
-
.example-desc { font-size: 13px; color: #334155; margin-bottom: 6px; }
|
|
1811
|
-
.example-code-row { display: flex; align-items: flex-start; gap: 8px; }
|
|
1812
|
-
.example-code { flex: 1; background: #f1f5f9; padding: 8px 12px; border-radius: 4px; font-family: monospace; font-size: 12px; color: #334155; overflow-x: auto; white-space: pre-wrap; }
|
|
1813
|
-
.copyable-prompt-section { margin-top: 12px; padding-top: 12px; border-top: 1px solid #e2e8f0; }
|
|
1814
|
-
.copyable-prompt-row { display: flex; align-items: flex-start; gap: 8px; }
|
|
1815
|
-
.copyable-prompt { flex: 1; background: #f8fafc; padding: 10px 12px; border-radius: 4px; font-family: monospace; font-size: 12px; color: #334155; border: 1px solid #e2e8f0; white-space: pre-wrap; line-height: 1.5; }
|
|
1816
|
-
.feature-code { background: #f8fafc; padding: 12px; border-radius: 6px; margin-top: 12px; border: 1px solid #e2e8f0; display: flex; align-items: flex-start; gap: 8px; }
|
|
1817
|
-
.feature-code code { flex: 1; font-family: monospace; font-size: 12px; color: #334155; white-space: pre-wrap; }
|
|
1818
|
-
.pattern-prompt { background: #f8fafc; padding: 12px; border-radius: 6px; margin-top: 12px; border: 1px solid #e2e8f0; }
|
|
1819
|
-
.pattern-prompt code { font-family: monospace; font-size: 12px; color: #334155; display: block; white-space: pre-wrap; margin-bottom: 8px; }
|
|
1820
|
-
.prompt-label { font-size: 11px; font-weight: 600; text-transform: uppercase; color: #64748b; margin-bottom: 6px; }
|
|
1821
|
-
.copy-btn { background: #e2e8f0; border: none; border-radius: 4px; padding: 4px 8px; font-size: 11px; cursor: pointer; color: #475569; flex-shrink: 0; }
|
|
1822
|
-
.copy-btn:hover { background: #cbd5e1; }
|
|
1823
|
-
.charts-row { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; margin: 24px 0; }
|
|
1824
|
-
.chart-card { background: white; border: 1px solid #e2e8f0; border-radius: 8px; padding: 16px; }
|
|
1825
|
-
.chart-title { font-size: 12px; font-weight: 600; color: #64748b; text-transform: uppercase; margin-bottom: 12px; }
|
|
1826
|
-
.bar-row { display: flex; align-items: center; margin-bottom: 6px; }
|
|
1827
|
-
.bar-label { width: 100px; font-size: 11px; color: #475569; flex-shrink: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
1828
|
-
.bar-track { flex: 1; height: 6px; background: #f1f5f9; border-radius: 3px; margin: 0 8px; }
|
|
1829
|
-
.bar-fill { height: 100%; border-radius: 3px; }
|
|
1830
|
-
.bar-value { width: 28px; font-size: 11px; font-weight: 500; color: #64748b; text-align: right; }
|
|
1831
|
-
.empty { color: #94a3b8; font-size: 13px; }
|
|
1832
|
-
.horizon-section { display: flex; flex-direction: column; gap: 16px; }
|
|
1833
|
-
.horizon-card { background: linear-gradient(135deg, #faf5ff 0%, #f5f3ff 100%); border: 1px solid #c4b5fd; border-radius: 8px; padding: 16px; }
|
|
1834
|
-
.horizon-title { font-weight: 600; font-size: 15px; color: #5b21b6; margin-bottom: 8px; }
|
|
1835
|
-
.horizon-possible { font-size: 14px; color: #334155; margin-bottom: 10px; line-height: 1.5; }
|
|
1836
|
-
.horizon-tip { font-size: 13px; color: #6b21a8; background: rgba(255,255,255,0.6); padding: 8px 12px; border-radius: 4px; }
|
|
1837
|
-
.feedback-header { margin-top: 48px; color: #64748b; font-size: 16px; }
|
|
1838
|
-
.feedback-intro { font-size: 13px; color: #94a3b8; margin-bottom: 16px; }
|
|
1839
|
-
.feedback-section { margin-top: 16px; }
|
|
1840
|
-
.feedback-section h3 { font-size: 14px; font-weight: 600; color: #475569; margin-bottom: 12px; }
|
|
1841
|
-
.feedback-card { background: white; border: 1px solid #e2e8f0; border-radius: 8px; padding: 16px; margin-bottom: 12px; }
|
|
1842
|
-
.feedback-card.team-card { background: #eff6ff; border-color: #bfdbfe; }
|
|
1843
|
-
.feedback-card.model-card { background: #faf5ff; border-color: #e9d5ff; }
|
|
1844
|
-
.feedback-title { font-weight: 600; font-size: 14px; color: #0f172a; margin-bottom: 6px; }
|
|
1845
|
-
.feedback-detail { font-size: 13px; color: #475569; line-height: 1.5; }
|
|
1846
|
-
.feedback-evidence { font-size: 12px; color: #64748b; margin-top: 8px; }
|
|
1847
|
-
.fun-ending { background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%); border: 1px solid #fbbf24; border-radius: 12px; padding: 24px; margin-top: 40px; text-align: center; }
|
|
1848
|
-
.fun-headline { font-size: 18px; font-weight: 600; color: #78350f; margin-bottom: 8px; }
|
|
1849
|
-
.fun-detail { font-size: 14px; color: #92400e; }
|
|
1850
|
-
.collapsible-section { margin-top: 16px; }
|
|
1851
|
-
.collapsible-header { display: flex; align-items: center; gap: 8px; cursor: pointer; padding: 12px 0; border-bottom: 1px solid #e2e8f0; }
|
|
1852
|
-
.collapsible-header h3 { margin: 0; font-size: 14px; font-weight: 600; color: #475569; }
|
|
1853
|
-
.collapsible-arrow { font-size: 12px; color: #94a3b8; transition: transform 0.2s; }
|
|
1854
|
-
.collapsible-content { display: none; padding-top: 16px; }
|
|
1855
|
-
.collapsible-content.open { display: block; }
|
|
1856
|
-
.collapsible-header.open .collapsible-arrow { transform: rotate(90deg); }
|
|
1857
|
-
@media (max-width: 640px) { .charts-row { grid-template-columns: 1fr; } .stats-row { justify-content: center; } }
|
|
1748
|
+
const css = `
|
|
1749
|
+
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
1750
|
+
body { font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif; background: #f8fafc; color: #334155; line-height: 1.65; padding: 48px 24px; }
|
|
1751
|
+
.container { max-width: 800px; margin: 0 auto; }
|
|
1752
|
+
h1 { font-size: 32px; font-weight: 700; color: #0f172a; margin-bottom: 8px; }
|
|
1753
|
+
h2 { font-size: 20px; font-weight: 600; color: #0f172a; margin-top: 48px; margin-bottom: 16px; }
|
|
1754
|
+
.subtitle { color: #64748b; font-size: 15px; margin-bottom: 32px; }
|
|
1755
|
+
.nav-toc { display: flex; flex-wrap: wrap; gap: 8px; margin: 24px 0 32px 0; padding: 16px; background: white; border-radius: 8px; border: 1px solid #e2e8f0; }
|
|
1756
|
+
.nav-toc a { font-size: 12px; color: #64748b; text-decoration: none; padding: 6px 12px; border-radius: 6px; background: #f1f5f9; transition: all 0.15s; }
|
|
1757
|
+
.nav-toc a:hover { background: #e2e8f0; color: #334155; }
|
|
1758
|
+
.stats-row { display: flex; gap: 24px; margin-bottom: 40px; padding: 20px 0; border-top: 1px solid #e2e8f0; border-bottom: 1px solid #e2e8f0; flex-wrap: wrap; }
|
|
1759
|
+
.stat { text-align: center; }
|
|
1760
|
+
.stat-value { font-size: 24px; font-weight: 700; color: #0f172a; }
|
|
1761
|
+
.stat-label { font-size: 11px; color: #64748b; text-transform: uppercase; }
|
|
1762
|
+
.at-a-glance { background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%); border: 1px solid #f59e0b; border-radius: 12px; padding: 20px 24px; margin-bottom: 32px; }
|
|
1763
|
+
.glance-title { font-size: 16px; font-weight: 700; color: #92400e; margin-bottom: 16px; }
|
|
1764
|
+
.glance-sections { display: flex; flex-direction: column; gap: 12px; }
|
|
1765
|
+
.glance-section { font-size: 14px; color: #78350f; line-height: 1.6; }
|
|
1766
|
+
.glance-section strong { color: #92400e; }
|
|
1767
|
+
.see-more { color: #b45309; text-decoration: none; font-size: 13px; white-space: nowrap; }
|
|
1768
|
+
.see-more:hover { text-decoration: underline; }
|
|
1769
|
+
.project-areas { display: flex; flex-direction: column; gap: 12px; margin-bottom: 32px; }
|
|
1770
|
+
.project-area { background: white; border: 1px solid #e2e8f0; border-radius: 8px; padding: 16px; }
|
|
1771
|
+
.area-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px; }
|
|
1772
|
+
.area-name { font-weight: 600; font-size: 15px; color: #0f172a; }
|
|
1773
|
+
.area-count { font-size: 12px; color: #64748b; background: #f1f5f9; padding: 2px 8px; border-radius: 4px; }
|
|
1774
|
+
.area-desc { font-size: 14px; color: #475569; line-height: 1.5; }
|
|
1775
|
+
.narrative { background: white; border: 1px solid #e2e8f0; border-radius: 8px; padding: 20px; margin-bottom: 24px; }
|
|
1776
|
+
.narrative p { margin-bottom: 12px; font-size: 14px; color: #475569; line-height: 1.7; }
|
|
1777
|
+
.key-insight { background: #f0fdf4; border: 1px solid #bbf7d0; border-radius: 8px; padding: 12px 16px; margin-top: 12px; font-size: 14px; color: #166534; }
|
|
1778
|
+
.section-intro { font-size: 14px; color: #64748b; margin-bottom: 16px; }
|
|
1779
|
+
.big-wins { display: flex; flex-direction: column; gap: 12px; margin-bottom: 24px; }
|
|
1780
|
+
.big-win { background: #f0fdf4; border: 1px solid #bbf7d0; border-radius: 8px; padding: 16px; }
|
|
1781
|
+
.big-win-title { font-weight: 600; font-size: 15px; color: #166534; margin-bottom: 8px; }
|
|
1782
|
+
.big-win-desc { font-size: 14px; color: #15803d; line-height: 1.5; }
|
|
1783
|
+
.friction-categories { display: flex; flex-direction: column; gap: 16px; margin-bottom: 24px; }
|
|
1784
|
+
.friction-category { background: #fef2f2; border: 1px solid #fca5a5; border-radius: 8px; padding: 16px; }
|
|
1785
|
+
.friction-title { font-weight: 600; font-size: 15px; color: #991b1b; margin-bottom: 6px; }
|
|
1786
|
+
.friction-desc { font-size: 13px; color: #7f1d1d; margin-bottom: 10px; }
|
|
1787
|
+
.friction-examples { margin: 0 0 0 20px; font-size: 13px; color: #334155; }
|
|
1788
|
+
.friction-examples li { margin-bottom: 4px; }
|
|
1789
|
+
.claude-md-section { background: #eff6ff; border: 1px solid #bfdbfe; border-radius: 8px; padding: 16px; margin-bottom: 20px; }
|
|
1790
|
+
.claude-md-section h3 { font-size: 14px; font-weight: 600; color: #1e40af; margin: 0 0 12px 0; }
|
|
1791
|
+
.claude-md-actions { margin-bottom: 12px; padding-bottom: 12px; border-bottom: 1px solid #dbeafe; }
|
|
1792
|
+
.copy-all-btn { background: #2563eb; color: white; border: none; border-radius: 4px; padding: 6px 12px; font-size: 12px; cursor: pointer; font-weight: 500; transition: all 0.2s; }
|
|
1793
|
+
.copy-all-btn:hover { background: #1d4ed8; }
|
|
1794
|
+
.copy-all-btn.copied { background: #16a34a; }
|
|
1795
|
+
.claude-md-item { display: flex; flex-wrap: wrap; align-items: flex-start; gap: 8px; padding: 10px 0; border-bottom: 1px solid #dbeafe; }
|
|
1796
|
+
.claude-md-item:last-child { border-bottom: none; }
|
|
1797
|
+
.cmd-checkbox { margin-top: 2px; }
|
|
1798
|
+
.cmd-code { background: white; padding: 8px 12px; border-radius: 4px; font-size: 12px; color: #1e40af; border: 1px solid #bfdbfe; font-family: monospace; display: block; white-space: pre-wrap; word-break: break-word; flex: 1; }
|
|
1799
|
+
.cmd-why { font-size: 12px; color: #64748b; width: 100%; padding-left: 24px; margin-top: 4px; }
|
|
1800
|
+
.features-section, .patterns-section { display: flex; flex-direction: column; gap: 12px; margin: 16px 0; }
|
|
1801
|
+
.feature-card { background: #f0fdf4; border: 1px solid #86efac; border-radius: 8px; padding: 16px; }
|
|
1802
|
+
.pattern-card { background: #f0f9ff; border: 1px solid #7dd3fc; border-radius: 8px; padding: 16px; }
|
|
1803
|
+
.feature-title, .pattern-title { font-weight: 600; font-size: 15px; color: #0f172a; margin-bottom: 6px; }
|
|
1804
|
+
.feature-oneliner { font-size: 14px; color: #475569; margin-bottom: 8px; }
|
|
1805
|
+
.pattern-summary { font-size: 14px; color: #475569; margin-bottom: 8px; }
|
|
1806
|
+
.feature-why, .pattern-detail { font-size: 13px; color: #334155; line-height: 1.5; }
|
|
1807
|
+
.feature-examples { margin-top: 12px; }
|
|
1808
|
+
.feature-example { padding: 8px 0; border-top: 1px solid #d1fae5; }
|
|
1809
|
+
.feature-example:first-child { border-top: none; }
|
|
1810
|
+
.example-desc { font-size: 13px; color: #334155; margin-bottom: 6px; }
|
|
1811
|
+
.example-code-row { display: flex; align-items: flex-start; gap: 8px; }
|
|
1812
|
+
.example-code { flex: 1; background: #f1f5f9; padding: 8px 12px; border-radius: 4px; font-family: monospace; font-size: 12px; color: #334155; overflow-x: auto; white-space: pre-wrap; }
|
|
1813
|
+
.copyable-prompt-section { margin-top: 12px; padding-top: 12px; border-top: 1px solid #e2e8f0; }
|
|
1814
|
+
.copyable-prompt-row { display: flex; align-items: flex-start; gap: 8px; }
|
|
1815
|
+
.copyable-prompt { flex: 1; background: #f8fafc; padding: 10px 12px; border-radius: 4px; font-family: monospace; font-size: 12px; color: #334155; border: 1px solid #e2e8f0; white-space: pre-wrap; line-height: 1.5; }
|
|
1816
|
+
.feature-code { background: #f8fafc; padding: 12px; border-radius: 6px; margin-top: 12px; border: 1px solid #e2e8f0; display: flex; align-items: flex-start; gap: 8px; }
|
|
1817
|
+
.feature-code code { flex: 1; font-family: monospace; font-size: 12px; color: #334155; white-space: pre-wrap; }
|
|
1818
|
+
.pattern-prompt { background: #f8fafc; padding: 12px; border-radius: 6px; margin-top: 12px; border: 1px solid #e2e8f0; }
|
|
1819
|
+
.pattern-prompt code { font-family: monospace; font-size: 12px; color: #334155; display: block; white-space: pre-wrap; margin-bottom: 8px; }
|
|
1820
|
+
.prompt-label { font-size: 11px; font-weight: 600; text-transform: uppercase; color: #64748b; margin-bottom: 6px; }
|
|
1821
|
+
.copy-btn { background: #e2e8f0; border: none; border-radius: 4px; padding: 4px 8px; font-size: 11px; cursor: pointer; color: #475569; flex-shrink: 0; }
|
|
1822
|
+
.copy-btn:hover { background: #cbd5e1; }
|
|
1823
|
+
.charts-row { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; margin: 24px 0; }
|
|
1824
|
+
.chart-card { background: white; border: 1px solid #e2e8f0; border-radius: 8px; padding: 16px; }
|
|
1825
|
+
.chart-title { font-size: 12px; font-weight: 600; color: #64748b; text-transform: uppercase; margin-bottom: 12px; }
|
|
1826
|
+
.bar-row { display: flex; align-items: center; margin-bottom: 6px; }
|
|
1827
|
+
.bar-label { width: 100px; font-size: 11px; color: #475569; flex-shrink: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
1828
|
+
.bar-track { flex: 1; height: 6px; background: #f1f5f9; border-radius: 3px; margin: 0 8px; }
|
|
1829
|
+
.bar-fill { height: 100%; border-radius: 3px; }
|
|
1830
|
+
.bar-value { width: 28px; font-size: 11px; font-weight: 500; color: #64748b; text-align: right; }
|
|
1831
|
+
.empty { color: #94a3b8; font-size: 13px; }
|
|
1832
|
+
.horizon-section { display: flex; flex-direction: column; gap: 16px; }
|
|
1833
|
+
.horizon-card { background: linear-gradient(135deg, #faf5ff 0%, #f5f3ff 100%); border: 1px solid #c4b5fd; border-radius: 8px; padding: 16px; }
|
|
1834
|
+
.horizon-title { font-weight: 600; font-size: 15px; color: #5b21b6; margin-bottom: 8px; }
|
|
1835
|
+
.horizon-possible { font-size: 14px; color: #334155; margin-bottom: 10px; line-height: 1.5; }
|
|
1836
|
+
.horizon-tip { font-size: 13px; color: #6b21a8; background: rgba(255,255,255,0.6); padding: 8px 12px; border-radius: 4px; }
|
|
1837
|
+
.feedback-header { margin-top: 48px; color: #64748b; font-size: 16px; }
|
|
1838
|
+
.feedback-intro { font-size: 13px; color: #94a3b8; margin-bottom: 16px; }
|
|
1839
|
+
.feedback-section { margin-top: 16px; }
|
|
1840
|
+
.feedback-section h3 { font-size: 14px; font-weight: 600; color: #475569; margin-bottom: 12px; }
|
|
1841
|
+
.feedback-card { background: white; border: 1px solid #e2e8f0; border-radius: 8px; padding: 16px; margin-bottom: 12px; }
|
|
1842
|
+
.feedback-card.team-card { background: #eff6ff; border-color: #bfdbfe; }
|
|
1843
|
+
.feedback-card.model-card { background: #faf5ff; border-color: #e9d5ff; }
|
|
1844
|
+
.feedback-title { font-weight: 600; font-size: 14px; color: #0f172a; margin-bottom: 6px; }
|
|
1845
|
+
.feedback-detail { font-size: 13px; color: #475569; line-height: 1.5; }
|
|
1846
|
+
.feedback-evidence { font-size: 12px; color: #64748b; margin-top: 8px; }
|
|
1847
|
+
.fun-ending { background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%); border: 1px solid #fbbf24; border-radius: 12px; padding: 24px; margin-top: 40px; text-align: center; }
|
|
1848
|
+
.fun-headline { font-size: 18px; font-weight: 600; color: #78350f; margin-bottom: 8px; }
|
|
1849
|
+
.fun-detail { font-size: 14px; color: #92400e; }
|
|
1850
|
+
.collapsible-section { margin-top: 16px; }
|
|
1851
|
+
.collapsible-header { display: flex; align-items: center; gap: 8px; cursor: pointer; padding: 12px 0; border-bottom: 1px solid #e2e8f0; }
|
|
1852
|
+
.collapsible-header h3 { margin: 0; font-size: 14px; font-weight: 600; color: #475569; }
|
|
1853
|
+
.collapsible-arrow { font-size: 12px; color: #94a3b8; transition: transform 0.2s; }
|
|
1854
|
+
.collapsible-content { display: none; padding-top: 16px; }
|
|
1855
|
+
.collapsible-content.open { display: block; }
|
|
1856
|
+
.collapsible-header.open .collapsible-arrow { transform: rotate(90deg); }
|
|
1857
|
+
@media (max-width: 640px) { .charts-row { grid-template-columns: 1fr; } .stats-row { justify-content: center; } }
|
|
1858
1858
|
`;
|
|
1859
1859
|
const hourCountsJson = getHourCountsJson(data.message_hours);
|
|
1860
|
-
const js = `
|
|
1861
|
-
function toggleCollapsible(header) {
|
|
1862
|
-
header.classList.toggle('open');
|
|
1863
|
-
const content = header.nextElementSibling;
|
|
1864
|
-
content.classList.toggle('open');
|
|
1865
|
-
}
|
|
1866
|
-
function copyText(btn) {
|
|
1867
|
-
const code = btn.previousElementSibling;
|
|
1868
|
-
navigator.clipboard.writeText(code.textContent).then(() => {
|
|
1869
|
-
btn.textContent = 'Copied!';
|
|
1870
|
-
setTimeout(() => { btn.textContent = 'Copy'; }, 2000);
|
|
1871
|
-
});
|
|
1872
|
-
}
|
|
1873
|
-
function copyCmdItem(idx) {
|
|
1874
|
-
const checkbox = document.getElementById('cmd-' + idx);
|
|
1875
|
-
if (checkbox) {
|
|
1876
|
-
const text = checkbox.dataset.text;
|
|
1877
|
-
navigator.clipboard.writeText(text).then(() => {
|
|
1878
|
-
const btn = checkbox.nextElementSibling.querySelector('.copy-btn');
|
|
1879
|
-
if (btn) { btn.textContent = 'Copied!'; setTimeout(() => { btn.textContent = 'Copy'; }, 2000); }
|
|
1880
|
-
});
|
|
1881
|
-
}
|
|
1882
|
-
}
|
|
1883
|
-
function copyAllCheckedClaudeMd() {
|
|
1884
|
-
const checkboxes = document.querySelectorAll('.cmd-checkbox:checked');
|
|
1885
|
-
const texts = [];
|
|
1886
|
-
checkboxes.forEach(cb => {
|
|
1887
|
-
if (cb.dataset.text) { texts.push(cb.dataset.text); }
|
|
1888
|
-
});
|
|
1889
|
-
const combined = texts.join('\\n');
|
|
1890
|
-
const btn = document.querySelector('.copy-all-btn');
|
|
1891
|
-
if (btn) {
|
|
1892
|
-
navigator.clipboard.writeText(combined).then(() => {
|
|
1893
|
-
btn.textContent = 'Copied ' + texts.length + ' items!';
|
|
1894
|
-
btn.classList.add('copied');
|
|
1895
|
-
setTimeout(() => { btn.textContent = 'Copy All Checked'; btn.classList.remove('copied'); }, 2000);
|
|
1896
|
-
});
|
|
1897
|
-
}
|
|
1898
|
-
}
|
|
1899
|
-
// Timezone selector for time of day chart (data is from our own analytics, not user input)
|
|
1900
|
-
const rawHourCounts = ${hourCountsJson};
|
|
1901
|
-
function updateHourHistogram(offsetFromPT) {
|
|
1902
|
-
const periods = [
|
|
1903
|
-
{ label: "Morning (6-12)", range: [6,7,8,9,10,11] },
|
|
1904
|
-
{ label: "Afternoon (12-18)", range: [12,13,14,15,16,17] },
|
|
1905
|
-
{ label: "Evening (18-24)", range: [18,19,20,21,22,23] },
|
|
1906
|
-
{ label: "Night (0-6)", range: [0,1,2,3,4,5] }
|
|
1907
|
-
];
|
|
1908
|
-
const adjustedCounts = {};
|
|
1909
|
-
for (const [hour, count] of Object.entries(rawHourCounts)) {
|
|
1910
|
-
const newHour = (parseInt(hour) + offsetFromPT + 24) % 24;
|
|
1911
|
-
adjustedCounts[newHour] = (adjustedCounts[newHour] || 0) + count;
|
|
1912
|
-
}
|
|
1913
|
-
const periodCounts = periods.map(p => ({
|
|
1914
|
-
label: p.label,
|
|
1915
|
-
count: p.range.reduce((sum, h) => sum + (adjustedCounts[h] || 0), 0)
|
|
1916
|
-
}));
|
|
1917
|
-
const maxCount = Math.max(...periodCounts.map(p => p.count)) || 1;
|
|
1918
|
-
const container = document.getElementById('hour-histogram');
|
|
1919
|
-
container.textContent = '';
|
|
1920
|
-
periodCounts.forEach(p => {
|
|
1921
|
-
const row = document.createElement('div');
|
|
1922
|
-
row.className = 'bar-row';
|
|
1923
|
-
const label = document.createElement('div');
|
|
1924
|
-
label.className = 'bar-label';
|
|
1925
|
-
label.textContent = p.label;
|
|
1926
|
-
const track = document.createElement('div');
|
|
1927
|
-
track.className = 'bar-track';
|
|
1928
|
-
const fill = document.createElement('div');
|
|
1929
|
-
fill.className = 'bar-fill';
|
|
1930
|
-
fill.style.width = (p.count / maxCount) * 100 + '%';
|
|
1931
|
-
fill.style.background = '#8b5cf6';
|
|
1932
|
-
track.appendChild(fill);
|
|
1933
|
-
const value = document.createElement('div');
|
|
1934
|
-
value.className = 'bar-value';
|
|
1935
|
-
value.textContent = p.count;
|
|
1936
|
-
row.appendChild(label);
|
|
1937
|
-
row.appendChild(track);
|
|
1938
|
-
row.appendChild(value);
|
|
1939
|
-
container.appendChild(row);
|
|
1940
|
-
});
|
|
1941
|
-
}
|
|
1942
|
-
document.getElementById('timezone-select').addEventListener('change', function() {
|
|
1943
|
-
const customInput = document.getElementById('custom-offset');
|
|
1944
|
-
if (this.value === 'custom') {
|
|
1945
|
-
customInput.style.display = 'inline-block';
|
|
1946
|
-
customInput.focus();
|
|
1947
|
-
} else {
|
|
1948
|
-
customInput.style.display = 'none';
|
|
1949
|
-
updateHourHistogram(parseInt(this.value));
|
|
1950
|
-
}
|
|
1951
|
-
});
|
|
1952
|
-
document.getElementById('custom-offset').addEventListener('change', function() {
|
|
1953
|
-
const offset = parseInt(this.value) + 8;
|
|
1954
|
-
updateHourHistogram(offset);
|
|
1955
|
-
});
|
|
1860
|
+
const js = `
|
|
1861
|
+
function toggleCollapsible(header) {
|
|
1862
|
+
header.classList.toggle('open');
|
|
1863
|
+
const content = header.nextElementSibling;
|
|
1864
|
+
content.classList.toggle('open');
|
|
1865
|
+
}
|
|
1866
|
+
function copyText(btn) {
|
|
1867
|
+
const code = btn.previousElementSibling;
|
|
1868
|
+
navigator.clipboard.writeText(code.textContent).then(() => {
|
|
1869
|
+
btn.textContent = 'Copied!';
|
|
1870
|
+
setTimeout(() => { btn.textContent = 'Copy'; }, 2000);
|
|
1871
|
+
});
|
|
1872
|
+
}
|
|
1873
|
+
function copyCmdItem(idx) {
|
|
1874
|
+
const checkbox = document.getElementById('cmd-' + idx);
|
|
1875
|
+
if (checkbox) {
|
|
1876
|
+
const text = checkbox.dataset.text;
|
|
1877
|
+
navigator.clipboard.writeText(text).then(() => {
|
|
1878
|
+
const btn = checkbox.nextElementSibling.querySelector('.copy-btn');
|
|
1879
|
+
if (btn) { btn.textContent = 'Copied!'; setTimeout(() => { btn.textContent = 'Copy'; }, 2000); }
|
|
1880
|
+
});
|
|
1881
|
+
}
|
|
1882
|
+
}
|
|
1883
|
+
function copyAllCheckedClaudeMd() {
|
|
1884
|
+
const checkboxes = document.querySelectorAll('.cmd-checkbox:checked');
|
|
1885
|
+
const texts = [];
|
|
1886
|
+
checkboxes.forEach(cb => {
|
|
1887
|
+
if (cb.dataset.text) { texts.push(cb.dataset.text); }
|
|
1888
|
+
});
|
|
1889
|
+
const combined = texts.join('\\n');
|
|
1890
|
+
const btn = document.querySelector('.copy-all-btn');
|
|
1891
|
+
if (btn) {
|
|
1892
|
+
navigator.clipboard.writeText(combined).then(() => {
|
|
1893
|
+
btn.textContent = 'Copied ' + texts.length + ' items!';
|
|
1894
|
+
btn.classList.add('copied');
|
|
1895
|
+
setTimeout(() => { btn.textContent = 'Copy All Checked'; btn.classList.remove('copied'); }, 2000);
|
|
1896
|
+
});
|
|
1897
|
+
}
|
|
1898
|
+
}
|
|
1899
|
+
// Timezone selector for time of day chart (data is from our own analytics, not user input)
|
|
1900
|
+
const rawHourCounts = ${hourCountsJson};
|
|
1901
|
+
function updateHourHistogram(offsetFromPT) {
|
|
1902
|
+
const periods = [
|
|
1903
|
+
{ label: "Morning (6-12)", range: [6,7,8,9,10,11] },
|
|
1904
|
+
{ label: "Afternoon (12-18)", range: [12,13,14,15,16,17] },
|
|
1905
|
+
{ label: "Evening (18-24)", range: [18,19,20,21,22,23] },
|
|
1906
|
+
{ label: "Night (0-6)", range: [0,1,2,3,4,5] }
|
|
1907
|
+
];
|
|
1908
|
+
const adjustedCounts = {};
|
|
1909
|
+
for (const [hour, count] of Object.entries(rawHourCounts)) {
|
|
1910
|
+
const newHour = (parseInt(hour) + offsetFromPT + 24) % 24;
|
|
1911
|
+
adjustedCounts[newHour] = (adjustedCounts[newHour] || 0) + count;
|
|
1912
|
+
}
|
|
1913
|
+
const periodCounts = periods.map(p => ({
|
|
1914
|
+
label: p.label,
|
|
1915
|
+
count: p.range.reduce((sum, h) => sum + (adjustedCounts[h] || 0), 0)
|
|
1916
|
+
}));
|
|
1917
|
+
const maxCount = Math.max(...periodCounts.map(p => p.count)) || 1;
|
|
1918
|
+
const container = document.getElementById('hour-histogram');
|
|
1919
|
+
container.textContent = '';
|
|
1920
|
+
periodCounts.forEach(p => {
|
|
1921
|
+
const row = document.createElement('div');
|
|
1922
|
+
row.className = 'bar-row';
|
|
1923
|
+
const label = document.createElement('div');
|
|
1924
|
+
label.className = 'bar-label';
|
|
1925
|
+
label.textContent = p.label;
|
|
1926
|
+
const track = document.createElement('div');
|
|
1927
|
+
track.className = 'bar-track';
|
|
1928
|
+
const fill = document.createElement('div');
|
|
1929
|
+
fill.className = 'bar-fill';
|
|
1930
|
+
fill.style.width = (p.count / maxCount) * 100 + '%';
|
|
1931
|
+
fill.style.background = '#8b5cf6';
|
|
1932
|
+
track.appendChild(fill);
|
|
1933
|
+
const value = document.createElement('div');
|
|
1934
|
+
value.className = 'bar-value';
|
|
1935
|
+
value.textContent = p.count;
|
|
1936
|
+
row.appendChild(label);
|
|
1937
|
+
row.appendChild(track);
|
|
1938
|
+
row.appendChild(value);
|
|
1939
|
+
container.appendChild(row);
|
|
1940
|
+
});
|
|
1941
|
+
}
|
|
1942
|
+
document.getElementById('timezone-select').addEventListener('change', function() {
|
|
1943
|
+
const customInput = document.getElementById('custom-offset');
|
|
1944
|
+
if (this.value === 'custom') {
|
|
1945
|
+
customInput.style.display = 'inline-block';
|
|
1946
|
+
customInput.focus();
|
|
1947
|
+
} else {
|
|
1948
|
+
customInput.style.display = 'none';
|
|
1949
|
+
updateHourHistogram(parseInt(this.value));
|
|
1950
|
+
}
|
|
1951
|
+
});
|
|
1952
|
+
document.getElementById('custom-offset').addEventListener('change', function() {
|
|
1953
|
+
const offset = parseInt(this.value) + 8;
|
|
1954
|
+
updateHourHistogram(offset);
|
|
1955
|
+
});
|
|
1956
1956
|
`;
|
|
1957
|
-
return `<!DOCTYPE html>
|
|
1958
|
-
<html>
|
|
1959
|
-
<head>
|
|
1960
|
-
<meta charset="utf-8">
|
|
1961
|
-
<title>Context Code Insights</title>
|
|
1962
|
-
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
|
1963
|
-
<style>${css}</style>
|
|
1964
|
-
</head>
|
|
1965
|
-
<body>
|
|
1966
|
-
<div class="container">
|
|
1967
|
-
<h1>Context Code Insights</h1>
|
|
1968
|
-
<p class="subtitle">${data.total_messages.toLocaleString()} messages across ${data.total_sessions} sessions${data.total_sessions_scanned && data.total_sessions_scanned > data.total_sessions ? ` (${data.total_sessions_scanned.toLocaleString()} total)` : ''} | ${data.date_range.start} to ${data.date_range.end}</p>
|
|
1969
|
-
|
|
1970
|
-
${atAGlanceHtml}
|
|
1971
|
-
|
|
1972
|
-
<nav class="nav-toc">
|
|
1973
|
-
<a href="#section-work">What You Work On</a>
|
|
1974
|
-
<a href="#section-usage">How You Use CC</a>
|
|
1975
|
-
<a href="#section-wins">Impressive Things</a>
|
|
1976
|
-
<a href="#section-friction">Where Things Go Wrong</a>
|
|
1977
|
-
<a href="#section-features">Features to Try</a>
|
|
1978
|
-
<a href="#section-patterns">New Usage Patterns</a>
|
|
1979
|
-
<a href="#section-horizon">On the Horizon</a>
|
|
1980
|
-
<a href="#section-feedback">Team Feedback</a>
|
|
1981
|
-
</nav>
|
|
1982
|
-
|
|
1983
|
-
<div class="stats-row">
|
|
1984
|
-
<div class="stat"><div class="stat-value">${data.total_messages.toLocaleString()}</div><div class="stat-label">Messages</div></div>
|
|
1985
|
-
<div class="stat"><div class="stat-value">+${data.total_lines_added.toLocaleString()}/-${data.total_lines_removed.toLocaleString()}</div><div class="stat-label">Lines</div></div>
|
|
1986
|
-
<div class="stat"><div class="stat-value">${data.total_files_modified}</div><div class="stat-label">Files</div></div>
|
|
1987
|
-
<div class="stat"><div class="stat-value">${data.days_active}</div><div class="stat-label">Days</div></div>
|
|
1988
|
-
<div class="stat"><div class="stat-value">${data.messages_per_day}</div><div class="stat-label">Msgs/Day</div></div>
|
|
1989
|
-
</div>
|
|
1990
|
-
|
|
1991
|
-
${projectAreasHtml}
|
|
1992
|
-
|
|
1993
|
-
<div class="charts-row">
|
|
1994
|
-
<div class="chart-card">
|
|
1995
|
-
<div class="chart-title">What You Wanted</div>
|
|
1996
|
-
${generateBarChart(data.goal_categories, '#2563eb')}
|
|
1997
|
-
</div>
|
|
1998
|
-
<div class="chart-card">
|
|
1999
|
-
<div class="chart-title">Top Tools Used</div>
|
|
2000
|
-
${generateBarChart(data.tool_counts, '#0891b2')}
|
|
2001
|
-
</div>
|
|
2002
|
-
</div>
|
|
2003
|
-
|
|
2004
|
-
<div class="charts-row">
|
|
2005
|
-
<div class="chart-card">
|
|
2006
|
-
<div class="chart-title">Languages</div>
|
|
2007
|
-
${generateBarChart(data.languages, '#10b981')}
|
|
2008
|
-
</div>
|
|
2009
|
-
<div class="chart-card">
|
|
2010
|
-
<div class="chart-title">Session Types</div>
|
|
2011
|
-
${generateBarChart(data.session_types || {}, '#8b5cf6')}
|
|
2012
|
-
</div>
|
|
2013
|
-
</div>
|
|
2014
|
-
|
|
2015
|
-
${interactionHtml}
|
|
2016
|
-
|
|
2017
|
-
<!-- Response Time Distribution -->
|
|
2018
|
-
<div class="chart-card" style="margin: 24px 0;">
|
|
2019
|
-
<div class="chart-title">User Response Time Distribution</div>
|
|
2020
|
-
${generateResponseTimeHistogram(data.user_response_times)}
|
|
2021
|
-
<div style="font-size: 12px; color: #64748b; margin-top: 8px;">
|
|
2022
|
-
Median: ${data.median_response_time.toFixed(1)}s • Average: ${data.avg_response_time.toFixed(1)}s
|
|
2023
|
-
</div>
|
|
2024
|
-
</div>
|
|
2025
|
-
|
|
2026
|
-
<!-- Multi-clauding Section (matching Python reference) -->
|
|
2027
|
-
<div class="chart-card" style="margin: 24px 0;">
|
|
2028
|
-
<div class="chart-title">Multi-Clauding (Parallel Sessions)</div>
|
|
1957
|
+
return `<!DOCTYPE html>
|
|
1958
|
+
<html>
|
|
1959
|
+
<head>
|
|
1960
|
+
<meta charset="utf-8">
|
|
1961
|
+
<title>Context Code Insights</title>
|
|
1962
|
+
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
|
1963
|
+
<style>${css}</style>
|
|
1964
|
+
</head>
|
|
1965
|
+
<body>
|
|
1966
|
+
<div class="container">
|
|
1967
|
+
<h1>Context Code Insights</h1>
|
|
1968
|
+
<p class="subtitle">${data.total_messages.toLocaleString()} messages across ${data.total_sessions} sessions${data.total_sessions_scanned && data.total_sessions_scanned > data.total_sessions ? ` (${data.total_sessions_scanned.toLocaleString()} total)` : ''} | ${data.date_range.start} to ${data.date_range.end}</p>
|
|
1969
|
+
|
|
1970
|
+
${atAGlanceHtml}
|
|
1971
|
+
|
|
1972
|
+
<nav class="nav-toc">
|
|
1973
|
+
<a href="#section-work">What You Work On</a>
|
|
1974
|
+
<a href="#section-usage">How You Use CC</a>
|
|
1975
|
+
<a href="#section-wins">Impressive Things</a>
|
|
1976
|
+
<a href="#section-friction">Where Things Go Wrong</a>
|
|
1977
|
+
<a href="#section-features">Features to Try</a>
|
|
1978
|
+
<a href="#section-patterns">New Usage Patterns</a>
|
|
1979
|
+
<a href="#section-horizon">On the Horizon</a>
|
|
1980
|
+
<a href="#section-feedback">Team Feedback</a>
|
|
1981
|
+
</nav>
|
|
1982
|
+
|
|
1983
|
+
<div class="stats-row">
|
|
1984
|
+
<div class="stat"><div class="stat-value">${data.total_messages.toLocaleString()}</div><div class="stat-label">Messages</div></div>
|
|
1985
|
+
<div class="stat"><div class="stat-value">+${data.total_lines_added.toLocaleString()}/-${data.total_lines_removed.toLocaleString()}</div><div class="stat-label">Lines</div></div>
|
|
1986
|
+
<div class="stat"><div class="stat-value">${data.total_files_modified}</div><div class="stat-label">Files</div></div>
|
|
1987
|
+
<div class="stat"><div class="stat-value">${data.days_active}</div><div class="stat-label">Days</div></div>
|
|
1988
|
+
<div class="stat"><div class="stat-value">${data.messages_per_day}</div><div class="stat-label">Msgs/Day</div></div>
|
|
1989
|
+
</div>
|
|
1990
|
+
|
|
1991
|
+
${projectAreasHtml}
|
|
1992
|
+
|
|
1993
|
+
<div class="charts-row">
|
|
1994
|
+
<div class="chart-card">
|
|
1995
|
+
<div class="chart-title">What You Wanted</div>
|
|
1996
|
+
${generateBarChart(data.goal_categories, '#2563eb')}
|
|
1997
|
+
</div>
|
|
1998
|
+
<div class="chart-card">
|
|
1999
|
+
<div class="chart-title">Top Tools Used</div>
|
|
2000
|
+
${generateBarChart(data.tool_counts, '#0891b2')}
|
|
2001
|
+
</div>
|
|
2002
|
+
</div>
|
|
2003
|
+
|
|
2004
|
+
<div class="charts-row">
|
|
2005
|
+
<div class="chart-card">
|
|
2006
|
+
<div class="chart-title">Languages</div>
|
|
2007
|
+
${generateBarChart(data.languages, '#10b981')}
|
|
2008
|
+
</div>
|
|
2009
|
+
<div class="chart-card">
|
|
2010
|
+
<div class="chart-title">Session Types</div>
|
|
2011
|
+
${generateBarChart(data.session_types || {}, '#8b5cf6')}
|
|
2012
|
+
</div>
|
|
2013
|
+
</div>
|
|
2014
|
+
|
|
2015
|
+
${interactionHtml}
|
|
2016
|
+
|
|
2017
|
+
<!-- Response Time Distribution -->
|
|
2018
|
+
<div class="chart-card" style="margin: 24px 0;">
|
|
2019
|
+
<div class="chart-title">User Response Time Distribution</div>
|
|
2020
|
+
${generateResponseTimeHistogram(data.user_response_times)}
|
|
2021
|
+
<div style="font-size: 12px; color: #64748b; margin-top: 8px;">
|
|
2022
|
+
Median: ${data.median_response_time.toFixed(1)}s • Average: ${data.avg_response_time.toFixed(1)}s
|
|
2023
|
+
</div>
|
|
2024
|
+
</div>
|
|
2025
|
+
|
|
2026
|
+
<!-- Multi-clauding Section (matching Python reference) -->
|
|
2027
|
+
<div class="chart-card" style="margin: 24px 0;">
|
|
2028
|
+
<div class="chart-title">Multi-Clauding (Parallel Sessions)</div>
|
|
2029
2029
|
${data.multi_clauding.overlap_events === 0
|
|
2030
|
-
? `
|
|
2031
|
-
<p style="font-size: 14px; color: #64748b; padding: 8px 0;">
|
|
2032
|
-
No parallel session usage detected. You typically work with one Context Code session at a time.
|
|
2033
|
-
</p>
|
|
2030
|
+
? `
|
|
2031
|
+
<p style="font-size: 14px; color: #64748b; padding: 8px 0;">
|
|
2032
|
+
No parallel session usage detected. You typically work with one Context Code session at a time.
|
|
2033
|
+
</p>
|
|
2034
2034
|
`
|
|
2035
|
-
: `
|
|
2036
|
-
<div style="display: flex; gap: 24px; margin: 12px 0;">
|
|
2037
|
-
<div style="text-align: center;">
|
|
2038
|
-
<div style="font-size: 24px; font-weight: 700; color: #7c3aed;">${data.multi_clauding.overlap_events}</div>
|
|
2039
|
-
<div style="font-size: 11px; color: #64748b; text-transform: uppercase;">Overlap Events</div>
|
|
2040
|
-
</div>
|
|
2041
|
-
<div style="text-align: center;">
|
|
2042
|
-
<div style="font-size: 24px; font-weight: 700; color: #7c3aed;">${data.multi_clauding.sessions_involved}</div>
|
|
2043
|
-
<div style="font-size: 11px; color: #64748b; text-transform: uppercase;">Sessions Involved</div>
|
|
2044
|
-
</div>
|
|
2045
|
-
<div style="text-align: center;">
|
|
2046
|
-
<div style="font-size: 24px; font-weight: 700; color: #7c3aed;">${data.total_messages > 0 ? Math.round((100 * data.multi_clauding.user_messages_during) / data.total_messages) : 0}%</div>
|
|
2047
|
-
<div style="font-size: 11px; color: #64748b; text-transform: uppercase;">Of Messages</div>
|
|
2048
|
-
</div>
|
|
2049
|
-
</div>
|
|
2050
|
-
<p style="font-size: 13px; color: #475569; margin-top: 12px;">
|
|
2051
|
-
You run multiple Context Code sessions simultaneously. Multi-clauding is detected when sessions
|
|
2052
|
-
overlap in time, suggesting parallel workflows.
|
|
2053
|
-
</p>
|
|
2054
|
-
`}
|
|
2055
|
-
</div>
|
|
2056
|
-
|
|
2057
|
-
<!-- Time of Day & Tool Errors -->
|
|
2058
|
-
<div class="charts-row">
|
|
2059
|
-
<div class="chart-card">
|
|
2060
|
-
<div class="chart-title" style="display: flex; align-items: center; gap: 12px;">
|
|
2061
|
-
User Messages by Time of Day
|
|
2062
|
-
<select id="timezone-select" style="font-size: 12px; padding: 4px 8px; border-radius: 4px; border: 1px solid #e2e8f0;">
|
|
2063
|
-
<option value="0">PT (UTC-8)</option>
|
|
2064
|
-
<option value="3">ET (UTC-5)</option>
|
|
2065
|
-
<option value="8">London (UTC)</option>
|
|
2066
|
-
<option value="9">CET (UTC+1)</option>
|
|
2067
|
-
<option value="17">Tokyo (UTC+9)</option>
|
|
2068
|
-
<option value="custom">Custom offset...</option>
|
|
2069
|
-
</select>
|
|
2070
|
-
<input type="number" id="custom-offset" placeholder="UTC offset" style="display: none; width: 80px; font-size: 12px; padding: 4px; border-radius: 4px; border: 1px solid #e2e8f0;">
|
|
2071
|
-
</div>
|
|
2072
|
-
${generateTimeOfDayChart(data.message_hours)}
|
|
2073
|
-
</div>
|
|
2074
|
-
<div class="chart-card">
|
|
2075
|
-
<div class="chart-title">Tool Errors Encountered</div>
|
|
2076
|
-
${Object.keys(data.tool_error_categories).length > 0 ? generateBarChart(data.tool_error_categories, '#dc2626') : '<p class="empty">No tool errors</p>'}
|
|
2077
|
-
</div>
|
|
2078
|
-
</div>
|
|
2079
|
-
|
|
2080
|
-
${whatWorksHtml}
|
|
2081
|
-
|
|
2082
|
-
<div class="charts-row">
|
|
2083
|
-
<div class="chart-card">
|
|
2084
|
-
<div class="chart-title">What Helped Most (Claude's Capabilities)</div>
|
|
2085
|
-
${generateBarChart(data.success, '#16a34a')}
|
|
2086
|
-
</div>
|
|
2087
|
-
<div class="chart-card">
|
|
2088
|
-
<div class="chart-title">Outcomes</div>
|
|
2089
|
-
${generateBarChart(data.outcomes, '#8b5cf6', 6, OUTCOME_ORDER)}
|
|
2090
|
-
</div>
|
|
2091
|
-
</div>
|
|
2092
|
-
|
|
2093
|
-
${frictionHtml}
|
|
2094
|
-
|
|
2095
|
-
<div class="charts-row">
|
|
2096
|
-
<div class="chart-card">
|
|
2097
|
-
<div class="chart-title">Primary Friction Types</div>
|
|
2098
|
-
${generateBarChart(data.friction, '#dc2626')}
|
|
2099
|
-
</div>
|
|
2100
|
-
<div class="chart-card">
|
|
2101
|
-
<div class="chart-title">Inferred Satisfaction (model-estimated)</div>
|
|
2102
|
-
${generateBarChart(data.satisfaction, '#eab308', 6, SATISFACTION_ORDER)}
|
|
2103
|
-
</div>
|
|
2104
|
-
</div>
|
|
2105
|
-
|
|
2106
|
-
${suggestionsHtml}
|
|
2107
|
-
|
|
2108
|
-
${horizonHtml}
|
|
2109
|
-
|
|
2110
|
-
${funEndingHtml}
|
|
2111
|
-
|
|
2112
|
-
${teamFeedbackHtml}
|
|
2113
|
-
</div>
|
|
2114
|
-
<script>${js}</script>
|
|
2115
|
-
</body>
|
|
2035
|
+
: `
|
|
2036
|
+
<div style="display: flex; gap: 24px; margin: 12px 0;">
|
|
2037
|
+
<div style="text-align: center;">
|
|
2038
|
+
<div style="font-size: 24px; font-weight: 700; color: #7c3aed;">${data.multi_clauding.overlap_events}</div>
|
|
2039
|
+
<div style="font-size: 11px; color: #64748b; text-transform: uppercase;">Overlap Events</div>
|
|
2040
|
+
</div>
|
|
2041
|
+
<div style="text-align: center;">
|
|
2042
|
+
<div style="font-size: 24px; font-weight: 700; color: #7c3aed;">${data.multi_clauding.sessions_involved}</div>
|
|
2043
|
+
<div style="font-size: 11px; color: #64748b; text-transform: uppercase;">Sessions Involved</div>
|
|
2044
|
+
</div>
|
|
2045
|
+
<div style="text-align: center;">
|
|
2046
|
+
<div style="font-size: 24px; font-weight: 700; color: #7c3aed;">${data.total_messages > 0 ? Math.round((100 * data.multi_clauding.user_messages_during) / data.total_messages) : 0}%</div>
|
|
2047
|
+
<div style="font-size: 11px; color: #64748b; text-transform: uppercase;">Of Messages</div>
|
|
2048
|
+
</div>
|
|
2049
|
+
</div>
|
|
2050
|
+
<p style="font-size: 13px; color: #475569; margin-top: 12px;">
|
|
2051
|
+
You run multiple Context Code sessions simultaneously. Multi-clauding is detected when sessions
|
|
2052
|
+
overlap in time, suggesting parallel workflows.
|
|
2053
|
+
</p>
|
|
2054
|
+
`}
|
|
2055
|
+
</div>
|
|
2056
|
+
|
|
2057
|
+
<!-- Time of Day & Tool Errors -->
|
|
2058
|
+
<div class="charts-row">
|
|
2059
|
+
<div class="chart-card">
|
|
2060
|
+
<div class="chart-title" style="display: flex; align-items: center; gap: 12px;">
|
|
2061
|
+
User Messages by Time of Day
|
|
2062
|
+
<select id="timezone-select" style="font-size: 12px; padding: 4px 8px; border-radius: 4px; border: 1px solid #e2e8f0;">
|
|
2063
|
+
<option value="0">PT (UTC-8)</option>
|
|
2064
|
+
<option value="3">ET (UTC-5)</option>
|
|
2065
|
+
<option value="8">London (UTC)</option>
|
|
2066
|
+
<option value="9">CET (UTC+1)</option>
|
|
2067
|
+
<option value="17">Tokyo (UTC+9)</option>
|
|
2068
|
+
<option value="custom">Custom offset...</option>
|
|
2069
|
+
</select>
|
|
2070
|
+
<input type="number" id="custom-offset" placeholder="UTC offset" style="display: none; width: 80px; font-size: 12px; padding: 4px; border-radius: 4px; border: 1px solid #e2e8f0;">
|
|
2071
|
+
</div>
|
|
2072
|
+
${generateTimeOfDayChart(data.message_hours)}
|
|
2073
|
+
</div>
|
|
2074
|
+
<div class="chart-card">
|
|
2075
|
+
<div class="chart-title">Tool Errors Encountered</div>
|
|
2076
|
+
${Object.keys(data.tool_error_categories).length > 0 ? generateBarChart(data.tool_error_categories, '#dc2626') : '<p class="empty">No tool errors</p>'}
|
|
2077
|
+
</div>
|
|
2078
|
+
</div>
|
|
2079
|
+
|
|
2080
|
+
${whatWorksHtml}
|
|
2081
|
+
|
|
2082
|
+
<div class="charts-row">
|
|
2083
|
+
<div class="chart-card">
|
|
2084
|
+
<div class="chart-title">What Helped Most (Claude's Capabilities)</div>
|
|
2085
|
+
${generateBarChart(data.success, '#16a34a')}
|
|
2086
|
+
</div>
|
|
2087
|
+
<div class="chart-card">
|
|
2088
|
+
<div class="chart-title">Outcomes</div>
|
|
2089
|
+
${generateBarChart(data.outcomes, '#8b5cf6', 6, OUTCOME_ORDER)}
|
|
2090
|
+
</div>
|
|
2091
|
+
</div>
|
|
2092
|
+
|
|
2093
|
+
${frictionHtml}
|
|
2094
|
+
|
|
2095
|
+
<div class="charts-row">
|
|
2096
|
+
<div class="chart-card">
|
|
2097
|
+
<div class="chart-title">Primary Friction Types</div>
|
|
2098
|
+
${generateBarChart(data.friction, '#dc2626')}
|
|
2099
|
+
</div>
|
|
2100
|
+
<div class="chart-card">
|
|
2101
|
+
<div class="chart-title">Inferred Satisfaction (model-estimated)</div>
|
|
2102
|
+
${generateBarChart(data.satisfaction, '#eab308', 6, SATISFACTION_ORDER)}
|
|
2103
|
+
</div>
|
|
2104
|
+
</div>
|
|
2105
|
+
|
|
2106
|
+
${suggestionsHtml}
|
|
2107
|
+
|
|
2108
|
+
${horizonHtml}
|
|
2109
|
+
|
|
2110
|
+
${funEndingHtml}
|
|
2111
|
+
|
|
2112
|
+
${teamFeedbackHtml}
|
|
2113
|
+
</div>
|
|
2114
|
+
<script>${js}</script>
|
|
2115
|
+
</body>
|
|
2116
2116
|
</html>`;
|
|
2117
2117
|
}
|
|
2118
2118
|
/**
|
|
@@ -2457,8 +2457,8 @@ const usageReport = {
|
|
|
2457
2457
|
catch {
|
|
2458
2458
|
// Upload failed - fall back to local file and show upload command
|
|
2459
2459
|
reportUrl = `file://${htmlPath}`;
|
|
2460
|
-
uploadHint = `\nAutomatic upload failed. Are you on the boron namespace? Try \`use-bo\` and ensure you've run \`sso\`.
|
|
2461
|
-
To share, run: ff cp ${htmlPath} ${s3Path}
|
|
2460
|
+
uploadHint = `\nAutomatic upload failed. Are you on the boron namespace? Try \`use-bo\` and ensure you've run \`sso\`.
|
|
2461
|
+
To share, run: ff cp ${htmlPath} ${s3Path}
|
|
2462
2462
|
Then access at: ${s3Url}`;
|
|
2463
2463
|
}
|
|
2464
2464
|
}
|
|
@@ -2491,48 +2491,48 @@ Then access at: ${s3Url}`;
|
|
|
2491
2491
|
// Build markdown summary from insights
|
|
2492
2492
|
const atAGlance = insights.at_a_glance;
|
|
2493
2493
|
const summaryText = atAGlance
|
|
2494
|
-
? `## At a Glance
|
|
2495
|
-
|
|
2496
|
-
${atAGlance.whats_working ? `**What's working:** ${atAGlance.whats_working} See _Impressive Things You Did_.` : ''}
|
|
2497
|
-
|
|
2498
|
-
${atAGlance.whats_hindering ? `**What's hindering you:** ${atAGlance.whats_hindering} See _Where Things Go Wrong_.` : ''}
|
|
2499
|
-
|
|
2500
|
-
${atAGlance.quick_wins ? `**Quick wins to try:** ${atAGlance.quick_wins} See _Features to Try_.` : ''}
|
|
2501
|
-
|
|
2494
|
+
? `## At a Glance
|
|
2495
|
+
|
|
2496
|
+
${atAGlance.whats_working ? `**What's working:** ${atAGlance.whats_working} See _Impressive Things You Did_.` : ''}
|
|
2497
|
+
|
|
2498
|
+
${atAGlance.whats_hindering ? `**What's hindering you:** ${atAGlance.whats_hindering} See _Where Things Go Wrong_.` : ''}
|
|
2499
|
+
|
|
2500
|
+
${atAGlance.quick_wins ? `**Quick wins to try:** ${atAGlance.quick_wins} See _Features to Try_.` : ''}
|
|
2501
|
+
|
|
2502
2502
|
${atAGlance.ambitious_workflows ? `**Ambitious workflows:** ${atAGlance.ambitious_workflows} See _On the Horizon_.` : ''}`
|
|
2503
2503
|
: '_No insights generated_';
|
|
2504
|
-
const header = `# Context Code Insights
|
|
2505
|
-
|
|
2506
|
-
${stats}
|
|
2507
|
-
${data.date_range.start} to ${data.date_range.end}
|
|
2508
|
-
${remoteInfo}
|
|
2504
|
+
const header = `# Context Code Insights
|
|
2505
|
+
|
|
2506
|
+
${stats}
|
|
2507
|
+
${data.date_range.start} to ${data.date_range.end}
|
|
2508
|
+
${remoteInfo}
|
|
2509
2509
|
`;
|
|
2510
|
-
const userSummary = `${header}${summaryText}
|
|
2511
|
-
|
|
2510
|
+
const userSummary = `${header}${summaryText}
|
|
2511
|
+
|
|
2512
2512
|
Your full shareable insights report is ready: ${reportUrl}${uploadHint}`;
|
|
2513
2513
|
// Return prompt for Claude to respond to
|
|
2514
2514
|
return [
|
|
2515
2515
|
{
|
|
2516
2516
|
type: 'text',
|
|
2517
|
-
text: `The user just ran /insights to generate a usage report analyzing their Context Code sessions.
|
|
2518
|
-
|
|
2519
|
-
Here is the full insights data:
|
|
2520
|
-
${jsonStringify(insights, null, 2)}
|
|
2521
|
-
|
|
2522
|
-
Report URL: ${reportUrl}
|
|
2523
|
-
HTML file: ${htmlPath}
|
|
2524
|
-
Facets directory: ${getFacetsDir()}
|
|
2525
|
-
|
|
2526
|
-
Here is what the user sees:
|
|
2527
|
-
${userSummary}
|
|
2528
|
-
|
|
2529
|
-
Now output the following message exactly:
|
|
2530
|
-
|
|
2531
|
-
<message>
|
|
2532
|
-
Your shareable insights report is ready:
|
|
2533
|
-
${reportUrl}${uploadHint}
|
|
2534
|
-
|
|
2535
|
-
Want to dig into any section or try one of the suggestions?
|
|
2517
|
+
text: `The user just ran /insights to generate a usage report analyzing their Context Code sessions.
|
|
2518
|
+
|
|
2519
|
+
Here is the full insights data:
|
|
2520
|
+
${jsonStringify(insights, null, 2)}
|
|
2521
|
+
|
|
2522
|
+
Report URL: ${reportUrl}
|
|
2523
|
+
HTML file: ${htmlPath}
|
|
2524
|
+
Facets directory: ${getFacetsDir()}
|
|
2525
|
+
|
|
2526
|
+
Here is what the user sees:
|
|
2527
|
+
${userSummary}
|
|
2528
|
+
|
|
2529
|
+
Now output the following message exactly:
|
|
2530
|
+
|
|
2531
|
+
<message>
|
|
2532
|
+
Your shareable insights report is ready:
|
|
2533
|
+
${reportUrl}${uploadHint}
|
|
2534
|
+
|
|
2535
|
+
Want to dig into any section or try one of the suggestions?
|
|
2536
2536
|
</message>`,
|
|
2537
2537
|
},
|
|
2538
2538
|
];
|