appostle-installer 0.0.19 → 0.0.21
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/dist/appostle.js +108 -126
- package/dist/appostle.js.map +2 -2
- package/dist/schema-templates/animations.md +32 -43
- package/dist/schema-templates/shadows.md +5 -0
- package/dist/schema-templates/shapes.md +8 -8
- package/dist/worker.js +216 -129
- package/dist/worker.js.map +2 -2
- package/package.json +1 -1
|
@@ -1,48 +1,37 @@
|
|
|
1
1
|
---
|
|
2
|
-
description:
|
|
3
|
-
variables:
|
|
4
|
-
- key: animation.entry
|
|
5
|
-
type: text
|
|
6
|
-
label: Entry Pattern
|
|
7
|
-
value: ""
|
|
8
|
-
section: visual
|
|
9
|
-
- key: animation.entry.distance
|
|
10
|
-
type: number
|
|
11
|
-
label: Entry TranslateY (px)
|
|
12
|
-
value: ""
|
|
13
|
-
section: visual
|
|
14
|
-
- key: animation.entry.stagger
|
|
15
|
-
type: number
|
|
16
|
-
label: Sibling Stagger (ms)
|
|
17
|
-
value: ""
|
|
18
|
-
section: visual
|
|
19
|
-
- key: animation.hover
|
|
20
|
-
type: text
|
|
21
|
-
label: Hover Pattern
|
|
22
|
-
value: ""
|
|
23
|
-
section: visual
|
|
24
|
-
- key: animation.scroll
|
|
25
|
-
type: text
|
|
26
|
-
label: Scroll Pattern
|
|
27
|
-
value: ""
|
|
28
|
-
section: visual
|
|
29
|
-
- key: animation.status
|
|
30
|
-
type: text
|
|
31
|
-
label: Status Pattern
|
|
32
|
-
value: ""
|
|
33
|
-
section: visual
|
|
34
|
-
- key: animation.signature
|
|
35
|
-
type: text
|
|
36
|
-
label: Signature Pattern
|
|
37
|
-
value: ""
|
|
38
|
-
section: visual
|
|
39
|
-
- key: animation.principles
|
|
40
|
-
type: text
|
|
41
|
-
label: Principles
|
|
42
|
-
value: ""
|
|
43
|
-
section: visual
|
|
2
|
+
description: Brand animation language. Each `## <name>` block is one animation with embedded HTML + CSS preview. Variable count per brand.
|
|
3
|
+
variables: []
|
|
44
4
|
---
|
|
45
5
|
|
|
46
6
|
# Animations
|
|
47
7
|
|
|
48
|
-
[1–2 sentence description of the
|
|
8
|
+
[1–2 sentence description of the motion language this brand uses: when motion matters, what it communicates, what stays still.]
|
|
9
|
+
|
|
10
|
+
## <animation-name>
|
|
11
|
+
|
|
12
|
+
Role: <signature|entry|hover|scroll|status|loop|other> (optional role hint — used by the brand-guide to mark emphasis)
|
|
13
|
+
|
|
14
|
+
[Optional 1–2 sentence description of when and where this animation is used.]
|
|
15
|
+
|
|
16
|
+
```html
|
|
17
|
+
<!-- The demo HTML for the brand-guide preview. Use a unique-enough class name. -->
|
|
18
|
+
<div class="my-anim-demo">Hello</div>
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
```css
|
|
22
|
+
/* The CSS that drives the demo. Trust your class names — they live inside an
|
|
23
|
+
isolated card. Reference the brand's CSS vars (--font-hero, --accent-base,
|
|
24
|
+
--ease-default, etc.) so the demo feels branded. Keyframe names must be
|
|
25
|
+
unique within this brand's animations.md. */
|
|
26
|
+
.my-anim-demo {
|
|
27
|
+
animation: my-anim 800ms var(--ease-default, ease-out) forwards;
|
|
28
|
+
}
|
|
29
|
+
@keyframes my-anim {
|
|
30
|
+
from { opacity: 0; transform: translateY(12px); }
|
|
31
|
+
to { opacity: 1; transform: translateY(0); }
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## <next-animation-name>
|
|
36
|
+
|
|
37
|
+
…declare as many `## <name>` sections as the brand actually uses. A brand with one distinctive animation declares one. A brand with twelve declares twelve.
|
|
@@ -24,12 +24,12 @@ variables:
|
|
|
24
24
|
value: medium
|
|
25
25
|
options: [sparse, medium, a-lot, loads]
|
|
26
26
|
section: visual
|
|
27
|
-
- key: brand.shape.shape-1.min
|
|
27
|
+
- key: brand.shape.shape-1.size-range.min
|
|
28
28
|
type: text
|
|
29
29
|
label: Min Size — % of Page Height
|
|
30
30
|
value: "10"
|
|
31
31
|
section: visual
|
|
32
|
-
- key: brand.shape.shape-1.max
|
|
32
|
+
- key: brand.shape.shape-1.size-range.max
|
|
33
33
|
type: text
|
|
34
34
|
label: Max Size — % of Page Height
|
|
35
35
|
value: "60"
|
|
@@ -62,12 +62,12 @@ variables:
|
|
|
62
62
|
value: medium
|
|
63
63
|
options: [sparse, medium, a-lot, loads]
|
|
64
64
|
section: visual
|
|
65
|
-
- key: brand.shape.shape-2.min
|
|
65
|
+
- key: brand.shape.shape-2.size-range.min
|
|
66
66
|
type: text
|
|
67
67
|
label: Min Size — % of Page Height
|
|
68
68
|
value: "10"
|
|
69
69
|
section: visual
|
|
70
|
-
- key: brand.shape.shape-2.max
|
|
70
|
+
- key: brand.shape.shape-2.size-range.max
|
|
71
71
|
type: text
|
|
72
72
|
label: Max Size — % of Page Height
|
|
73
73
|
value: "60"
|
|
@@ -100,12 +100,12 @@ variables:
|
|
|
100
100
|
value: medium
|
|
101
101
|
options: [sparse, medium, a-lot, loads]
|
|
102
102
|
section: visual
|
|
103
|
-
- key: brand.shape.shape-3.min
|
|
103
|
+
- key: brand.shape.shape-3.size-range.min
|
|
104
104
|
type: text
|
|
105
105
|
label: Min Size — % of Page Height
|
|
106
106
|
value: "10"
|
|
107
107
|
section: visual
|
|
108
|
-
- key: brand.shape.shape-3.max
|
|
108
|
+
- key: brand.shape.shape-3.size-range.max
|
|
109
109
|
type: text
|
|
110
110
|
label: Max Size — % of Page Height
|
|
111
111
|
value: "60"
|
|
@@ -138,12 +138,12 @@ variables:
|
|
|
138
138
|
value: medium
|
|
139
139
|
options: [sparse, medium, a-lot, loads]
|
|
140
140
|
section: visual
|
|
141
|
-
- key: brand.shape.shape-4.min
|
|
141
|
+
- key: brand.shape.shape-4.size-range.min
|
|
142
142
|
type: text
|
|
143
143
|
label: Min Size — % of Page Height
|
|
144
144
|
value: "10"
|
|
145
145
|
section: visual
|
|
146
|
-
- key: brand.shape.shape-4.max
|
|
146
|
+
- key: brand.shape.shape-4.size-range.max
|
|
147
147
|
type: text
|
|
148
148
|
label: Max Size — % of Page Height
|
|
149
149
|
value: "60"
|
package/dist/worker.js
CHANGED
|
@@ -2578,6 +2578,10 @@ function toAgentPayload(agent, options) {
|
|
|
2578
2578
|
title: options?.title ?? null,
|
|
2579
2579
|
labels: agent.labels,
|
|
2580
2580
|
internal: agent.internal,
|
|
2581
|
+
// Forward archivedAt on the live broadcast so paired clients (e.g. mobile)
|
|
2582
|
+
// see the archive land — without this, only the device that ran the
|
|
2583
|
+
// archive mutation knows about it.
|
|
2584
|
+
archivedAt: agent.archivedAt ?? null,
|
|
2581
2585
|
// Surface ownership so the client can render an owner badge / detect
|
|
2582
2586
|
// "shared with me" agents. `sharedWithUserIds` deliberately stays off
|
|
2583
2587
|
// the snapshot — only owners read the full ACL, via the dedicated
|
|
@@ -4235,6 +4239,7 @@ var GoogleFontsDownloadResponseSchema = z10.object({
|
|
|
4235
4239
|
});
|
|
4236
4240
|
|
|
4237
4241
|
// ../server/src/shared/messages.ts
|
|
4242
|
+
var InitialAgentSnapshotPageLimit = 200;
|
|
4238
4243
|
var MutableDaemonConfigSchema = z11.object({
|
|
4239
4244
|
mcp: z11.object({
|
|
4240
4245
|
injectIntoAgents: z11.boolean()
|
|
@@ -6727,6 +6732,17 @@ var FetchAgentsResponseMessageSchema = z11.object({
|
|
|
6727
6732
|
})
|
|
6728
6733
|
})
|
|
6729
6734
|
});
|
|
6735
|
+
var InitialAgentSnapshotMessageSchema = z11.object({
|
|
6736
|
+
type: z11.literal("initial_agent_snapshot"),
|
|
6737
|
+
payload: z11.object({
|
|
6738
|
+
entries: z11.array(
|
|
6739
|
+
z11.object({
|
|
6740
|
+
agent: AgentSnapshotPayloadSchema,
|
|
6741
|
+
project: ProjectPlacementPayloadSchema
|
|
6742
|
+
})
|
|
6743
|
+
)
|
|
6744
|
+
})
|
|
6745
|
+
});
|
|
6730
6746
|
var FetchWorkspacesResponseMessageSchema = z11.object({
|
|
6731
6747
|
type: z11.literal("fetch_workspaces_response"),
|
|
6732
6748
|
payload: z11.object({
|
|
@@ -7768,6 +7784,7 @@ var SessionOutboundMessageSchema = z11.discriminatedUnion("type", [
|
|
|
7768
7784
|
AgentStreamMessageSchema,
|
|
7769
7785
|
AgentStatusMessageSchema,
|
|
7770
7786
|
FetchAgentsResponseMessageSchema,
|
|
7787
|
+
InitialAgentSnapshotMessageSchema,
|
|
7771
7788
|
FetchWorkspacesResponseMessageSchema,
|
|
7772
7789
|
OpenProjectResponseMessageSchema,
|
|
7773
7790
|
StartWorkspaceScriptResponseMessageSchema,
|
|
@@ -20929,11 +20946,53 @@ var ClaudeAgentSession = class {
|
|
|
20929
20946
|
// sub-agents stop announcing them as suspected prompt injections. See
|
|
20930
20947
|
// getSystemReminderGuidance for the full rationale.
|
|
20931
20948
|
getSystemReminderGuidance(),
|
|
20932
|
-
|
|
20933
|
-
|
|
20949
|
+
//
|
|
20950
|
+
//
|
|
20951
|
+
//
|
|
20952
|
+
//
|
|
20953
|
+
// ╔══════════════════════════════════════════════════════════════════╗
|
|
20954
|
+
// ║ CUSTOM INSTRUCTIONS — add new system prompt lines below here ║
|
|
20955
|
+
// ║ Each line is a quoted string: "your instruction here", ║
|
|
20956
|
+
// ╚══════════════════════════════════════════════════════════════════╝
|
|
20957
|
+
//
|
|
20958
|
+
//
|
|
20959
|
+
//
|
|
20960
|
+
//
|
|
20961
|
+
"Default response shape: open with a short, scannable plain-English read. 2\u20134 short sentences, one idea each, no comma-chained clauses or em-dash pile-ups. When the read covers 3+ discrete points, use bullets instead of prose. Then the technical detail in dense form (paths, line refs, code) without narration. Don\u2019t explain what well-named code already explains. Skip the shape for trivial questions.",
|
|
20962
|
+
//
|
|
20934
20963
|
"When the user sends `>learn`, re-explain your previous message in plain English only \u2014 1 short paragraph that helps them build the mental model. No code, no file references, no technical repeat.",
|
|
20964
|
+
//
|
|
20965
|
+
//
|
|
20966
|
+
//
|
|
20967
|
+
//
|
|
20968
|
+
// ╔══════════════════════════════════════════════════════════════════╗
|
|
20969
|
+
// ║ END CUSTOM INSTRUCTIONS — don't edit below this line ║
|
|
20970
|
+
// ╚══════════════════════════════════════════════════════════════════╝
|
|
20971
|
+
//
|
|
20972
|
+
//
|
|
20973
|
+
//
|
|
20974
|
+
//
|
|
20935
20975
|
this.config.systemPrompt?.trim()
|
|
20936
20976
|
].filter((entry) => typeof entry === "string" && entry.length > 0).join("\n\n");
|
|
20977
|
+
const appostleAgents = {
|
|
20978
|
+
researcher: {
|
|
20979
|
+
description: "Use this agent when you need to explore unfamiliar code, trace data flow across modules, search broadly across the codebase, or read more than 2 files you haven't seen yet. Delegate investigation work here to keep the main conversation context lean.",
|
|
20980
|
+
prompt: "You are a codebase researcher. Your job is to investigate, trace, and report findings \u2014 never edit files. Read code, grep for patterns, follow imports, and build a clear picture. Report back a concise summary of what you found: key files, relevant code paths, and your conclusion. Keep your report under 300 words unless the investigation is complex.",
|
|
20981
|
+
model: "sonnet"
|
|
20982
|
+
},
|
|
20983
|
+
refactorer: {
|
|
20984
|
+
description: "Use this agent for refactors that touch more than 2 files \u2014 renames, migrations, pattern replacements, moving code between modules. Delegate multi-file changes here to isolate the blast radius.",
|
|
20985
|
+
prompt: "You are a refactoring specialist. Make the requested changes across all affected files. Be thorough \u2014 update imports, references, types, and tests. Run typecheck after changes if available. Report what you changed and any issues found."
|
|
20986
|
+
},
|
|
20987
|
+
reviewer: {
|
|
20988
|
+
description: "Use this agent to review code for bugs, security issues, performance problems, or style violations. Use it before committing large changes or when the user asks for a review.",
|
|
20989
|
+
prompt: "You are a code reviewer. Analyze the code for correctness, security vulnerabilities (OWASP top 10), performance issues, and adherence to the project's coding standards. Be specific \u2014 cite file paths and line numbers. Flag severity: critical, warning, or nitpick. Keep the review focused and actionable."
|
|
20990
|
+
},
|
|
20991
|
+
debugger: {
|
|
20992
|
+
description: "Use this agent to investigate bugs \u2014 read logs, trace error paths, check database state, reproduce issues. Delegate debugging here when the root cause isn't obvious from a quick look.",
|
|
20993
|
+
prompt: "You are a debugger. Your job is to find the root cause, not patch symptoms. Check real data first \u2014 logs, network requests, database state. Trace the full lifecycle of the bug. Present your findings: root cause, evidence, and a proposed minimal fix. Do not edit files unless explicitly asked."
|
|
20994
|
+
}
|
|
20995
|
+
};
|
|
20937
20996
|
const claudeBinary = await findExecutable("claude");
|
|
20938
20997
|
this.logger.debug(
|
|
20939
20998
|
{
|
|
@@ -20951,7 +21010,7 @@ var ClaudeAgentSession = class {
|
|
|
20951
21010
|
// bypass launch capability available so later setPermissionMode("bypassPermissions")
|
|
20952
21011
|
// calls do not fail after a model/thinking/rewind-driven restart.
|
|
20953
21012
|
allowDangerouslySkipPermissions: true,
|
|
20954
|
-
agents: this.defaults?.agents,
|
|
21013
|
+
agents: { ...appostleAgents, ...this.defaults?.agents },
|
|
20955
21014
|
canUseTool: this.handlePermissionRequest,
|
|
20956
21015
|
...claudeBinary ? { pathToClaudeCodeExecutable: claudeBinary } : {},
|
|
20957
21016
|
// Use Claude Code preset system prompt and load CLAUDE.md files
|
|
@@ -33556,7 +33615,7 @@ function serializeFrontmatter(input) {
|
|
|
33556
33615
|
|
|
33557
33616
|
// ../server/src/server/agent/handoff-mcp.ts
|
|
33558
33617
|
function buildHandoffMcpServer(callerAgentId, options) {
|
|
33559
|
-
const { agentManager, appostleHome, logger } = options;
|
|
33618
|
+
const { agentManager, appostleHome, logger, agentStorage } = options;
|
|
33560
33619
|
const log = logger.child({ module: "handoff-mcp", callerAgentId });
|
|
33561
33620
|
const handoffTool = tool2(
|
|
33562
33621
|
"handoff",
|
|
@@ -33635,6 +33694,22 @@ function buildHandoffMcpServer(callerAgentId, options) {
|
|
|
33635
33694
|
} catch (err) {
|
|
33636
33695
|
log.error({ err, agentId: snapshot.id }, "handoff: failed to start run");
|
|
33637
33696
|
}
|
|
33697
|
+
if (agentStorage) {
|
|
33698
|
+
try {
|
|
33699
|
+
setupFinishNotification({
|
|
33700
|
+
agentManager,
|
|
33701
|
+
agentStorage,
|
|
33702
|
+
childAgentId: snapshot.id,
|
|
33703
|
+
callerAgentId,
|
|
33704
|
+
logger: log
|
|
33705
|
+
});
|
|
33706
|
+
} catch (err) {
|
|
33707
|
+
log.error(
|
|
33708
|
+
{ err, agentId: snapshot.id },
|
|
33709
|
+
"handoff: failed to wire auto-return notification"
|
|
33710
|
+
);
|
|
33711
|
+
}
|
|
33712
|
+
}
|
|
33638
33713
|
return {
|
|
33639
33714
|
content: [
|
|
33640
33715
|
{
|
|
@@ -33645,11 +33720,97 @@ function buildHandoffMcpServer(callerAgentId, options) {
|
|
|
33645
33720
|
};
|
|
33646
33721
|
}
|
|
33647
33722
|
);
|
|
33723
|
+
const reportTool = tool2(
|
|
33724
|
+
"report",
|
|
33725
|
+
[
|
|
33726
|
+
"Send a curated message from this handoff child session back to its parent.",
|
|
33727
|
+
"Use this when the user types `>report` \u2014 they want to deliver a specific update",
|
|
33728
|
+
"to the parent right now, in their own words.",
|
|
33729
|
+
"",
|
|
33730
|
+
"Independent of the automatic on-finish notification: the parent still receives",
|
|
33731
|
+
"the auto-return when this child eventually finishes. You can call this tool any",
|
|
33732
|
+
"number of times over the lifetime of the handoff \u2014 each call is a separate",
|
|
33733
|
+
"update.",
|
|
33734
|
+
"",
|
|
33735
|
+
"Only works in sessions that were spawned via `handoff`. Errors otherwise."
|
|
33736
|
+
].join("\n"),
|
|
33737
|
+
{
|
|
33738
|
+
message: z33.string().min(1).describe(
|
|
33739
|
+
"The curated report to deliver to the parent session. Self-contained: the parent does not see this conversation's timeline."
|
|
33740
|
+
)
|
|
33741
|
+
},
|
|
33742
|
+
async (args) => {
|
|
33743
|
+
const childAgent = agentManager.getAgent(callerAgentId);
|
|
33744
|
+
if (!childAgent) {
|
|
33745
|
+
return {
|
|
33746
|
+
isError: true,
|
|
33747
|
+
content: [
|
|
33748
|
+
{ type: "text", text: `Caller agent ${callerAgentId} not found in agent manager` }
|
|
33749
|
+
]
|
|
33750
|
+
};
|
|
33751
|
+
}
|
|
33752
|
+
const parentAgentId = childAgent.labels?.["appostle.parent-agent-id"];
|
|
33753
|
+
if (!parentAgentId) {
|
|
33754
|
+
return {
|
|
33755
|
+
isError: true,
|
|
33756
|
+
content: [
|
|
33757
|
+
{
|
|
33758
|
+
type: "text",
|
|
33759
|
+
text: "This session was not spawned via `handoff`, so there is no parent to report to."
|
|
33760
|
+
}
|
|
33761
|
+
]
|
|
33762
|
+
};
|
|
33763
|
+
}
|
|
33764
|
+
const parentAgent = agentManager.getAgent(parentAgentId);
|
|
33765
|
+
if (!parentAgent) {
|
|
33766
|
+
return {
|
|
33767
|
+
isError: true,
|
|
33768
|
+
content: [
|
|
33769
|
+
{
|
|
33770
|
+
type: "text",
|
|
33771
|
+
text: `Parent agent ${parentAgentId} is no longer available.`
|
|
33772
|
+
}
|
|
33773
|
+
]
|
|
33774
|
+
};
|
|
33775
|
+
}
|
|
33776
|
+
const childTitle = childAgent.config?.title ?? callerAgentId;
|
|
33777
|
+
const trimmedMessage = args.message.trim();
|
|
33778
|
+
const prompt = `<appostle-system>
|
|
33779
|
+
Agent ${callerAgentId} (${childTitle}) reported back:
|
|
33780
|
+
|
|
33781
|
+
${trimmedMessage}
|
|
33782
|
+
</appostle-system>`;
|
|
33783
|
+
try {
|
|
33784
|
+
startAgentRun(agentManager, parentAgentId, prompt, log, {
|
|
33785
|
+
replaceRunning: true
|
|
33786
|
+
});
|
|
33787
|
+
} catch (err) {
|
|
33788
|
+
log.error({ err, parentAgentId }, "report: failed to inject prompt into parent");
|
|
33789
|
+
return {
|
|
33790
|
+
isError: true,
|
|
33791
|
+
content: [
|
|
33792
|
+
{
|
|
33793
|
+
type: "text",
|
|
33794
|
+
text: `report failed: could not wake parent \u2014 ${err instanceof Error ? err.message : String(err)}`
|
|
33795
|
+
}
|
|
33796
|
+
]
|
|
33797
|
+
};
|
|
33798
|
+
}
|
|
33799
|
+
return {
|
|
33800
|
+
content: [
|
|
33801
|
+
{
|
|
33802
|
+
type: "text",
|
|
33803
|
+
text: `Reported to parent ${parentAgentId}.`
|
|
33804
|
+
}
|
|
33805
|
+
]
|
|
33806
|
+
};
|
|
33807
|
+
}
|
|
33808
|
+
);
|
|
33648
33809
|
const writePlanTool = buildWritePlanTool(callerAgentId, { agentManager, logger });
|
|
33649
33810
|
const sdkInstance = createSdkMcpServer({
|
|
33650
33811
|
name: "appostle",
|
|
33651
33812
|
version: "0.1.0",
|
|
33652
|
-
tools: [handoffTool, writePlanTool],
|
|
33813
|
+
tools: [handoffTool, reportTool, writePlanTool],
|
|
33653
33814
|
alwaysLoad: true
|
|
33654
33815
|
});
|
|
33655
33816
|
return {
|
|
@@ -34210,7 +34371,8 @@ var AgentManager = class {
|
|
|
34210
34371
|
mcpServers.appostle = buildHandoffMcpServer(agentId, {
|
|
34211
34372
|
agentManager: this,
|
|
34212
34373
|
appostleHome: this.appostleHome,
|
|
34213
|
-
logger: this.logger
|
|
34374
|
+
logger: this.logger,
|
|
34375
|
+
agentStorage: this.registry
|
|
34214
34376
|
});
|
|
34215
34377
|
}
|
|
34216
34378
|
return { ...config, mcpServers };
|
|
@@ -34809,6 +34971,7 @@ var AgentManager = class {
|
|
|
34809
34971
|
attentionReason: null,
|
|
34810
34972
|
attentionTimestamp: null
|
|
34811
34973
|
});
|
|
34974
|
+
agent.archivedAt = archivedAt;
|
|
34812
34975
|
this.notifyAgentState(agentId);
|
|
34813
34976
|
await this.closeAgent(agentId);
|
|
34814
34977
|
return { archivedAt };
|
|
@@ -40565,71 +40728,28 @@ function buildStructuralContext(allBrands) {
|
|
|
40565
40728
|
return lines.length > 0 ? lines.join("\n") : "(No structural context established yet.)";
|
|
40566
40729
|
}
|
|
40567
40730
|
var TARGET_QUESTIONS = 7;
|
|
40568
|
-
|
|
40569
|
-
|
|
40570
|
-
|
|
40571
|
-
|
|
40572
|
-
|
|
40573
|
-
|
|
40574
|
-
- Should the hero have scroll-triggered behavior or stay static?
|
|
40575
|
-
|
|
40576
|
-
## Section Variation & Flow
|
|
40577
|
-
- How many distinct section types should the page cycle through?
|
|
40578
|
-
- Should any sections break out of the main container (full-bleed moments)?
|
|
40579
|
-
|
|
40580
|
-
## Density & Spacing
|
|
40581
|
-
- How tight should content be packed within sections?
|
|
40582
|
-
- How much vertical breathing room between major sections?
|
|
40583
|
-
|
|
40584
|
-
## Grid System
|
|
40585
|
-
- What grid philosophy \u2014 strict 12-column, asymmetric, modular, or freeform?
|
|
40586
|
-
|
|
40587
|
-
## Containers & Cards
|
|
40588
|
-
- What's your card philosophy \u2014 flat, elevated, outlined, or glassmorphic?
|
|
40589
|
-
|
|
40590
|
-
## Image Treatment
|
|
40591
|
-
- What role do images play \u2014 hero-level, supporting, or minimal?
|
|
40592
|
-
|
|
40593
|
-
## CTA Strategy
|
|
40594
|
-
- How many CTAs per page and what's the hierarchy?
|
|
40595
|
-
|
|
40596
|
-
## Mobile Behavior
|
|
40597
|
-
- How should the desktop layout transform on mobile?
|
|
40598
|
-
|
|
40599
|
-
## Prohibitions & Bans
|
|
40600
|
-
- What design patterns are absolutely forbidden?
|
|
40601
|
-
- Any CSS properties or techniques that are banned?`;
|
|
40602
|
-
async function loadQaQuestions(logger) {
|
|
40603
|
-
const filePath = await findFileUpward(QA_FILENAME);
|
|
40604
|
-
if (filePath) {
|
|
40605
|
-
try {
|
|
40606
|
-
const content = await fs15.readFile(filePath, "utf8");
|
|
40607
|
-
logger.debug({ filePath }, "layout-generator: loaded Q&A questions from disk");
|
|
40608
|
-
return content;
|
|
40609
|
-
} catch (err) {
|
|
40610
|
-
logger.warn(
|
|
40611
|
-
{ err, filePath },
|
|
40612
|
-
"layout-generator: failed to read Q&A file; using embedded fallback"
|
|
40613
|
-
);
|
|
40614
|
-
}
|
|
40731
|
+
async function loadSpecFile(filename, logger) {
|
|
40732
|
+
const filePath = await findFileUpward(filename);
|
|
40733
|
+
if (!filePath) {
|
|
40734
|
+
throw new Error(
|
|
40735
|
+
`layout-generator: ${filename} not found by walking up from ${fileURLToPath3(import.meta.url)}. This file is the canonical spec and must exist at the appostle repo root.`
|
|
40736
|
+
);
|
|
40615
40737
|
}
|
|
40616
|
-
|
|
40738
|
+
try {
|
|
40739
|
+
const content = await fs15.readFile(filePath, "utf8");
|
|
40740
|
+
logger.debug({ filePath }, `layout-generator: loaded ${filename} from disk`);
|
|
40741
|
+
return content;
|
|
40742
|
+
} catch (err) {
|
|
40743
|
+
throw new Error(
|
|
40744
|
+
`layout-generator: failed to read ${filename} at ${filePath}: ${err.message}`
|
|
40745
|
+
);
|
|
40746
|
+
}
|
|
40747
|
+
}
|
|
40748
|
+
async function loadQaQuestions(logger) {
|
|
40749
|
+
return loadSpecFile(QA_FILENAME, logger);
|
|
40617
40750
|
}
|
|
40618
40751
|
async function loadLayoutPrompt(logger) {
|
|
40619
|
-
|
|
40620
|
-
if (filePath) {
|
|
40621
|
-
try {
|
|
40622
|
-
const content = await fs15.readFile(filePath, "utf8");
|
|
40623
|
-
logger.debug({ filePath }, "layout-generator: loaded layout prompt from disk");
|
|
40624
|
-
return content;
|
|
40625
|
-
} catch (err) {
|
|
40626
|
-
logger.warn(
|
|
40627
|
-
{ err, filePath },
|
|
40628
|
-
"layout-generator: failed to read layout-prompt file; using embedded fallback"
|
|
40629
|
-
);
|
|
40630
|
-
}
|
|
40631
|
-
}
|
|
40632
|
-
return EMBEDDED_LAYOUT_PROMPT_FALLBACK;
|
|
40752
|
+
return loadSpecFile(PROMPT_FILENAME, logger);
|
|
40633
40753
|
}
|
|
40634
40754
|
function interpolateTemplate(template, vars) {
|
|
40635
40755
|
let out = template;
|
|
@@ -40638,66 +40758,6 @@ function interpolateTemplate(template, vars) {
|
|
|
40638
40758
|
}
|
|
40639
40759
|
return out;
|
|
40640
40760
|
}
|
|
40641
|
-
var EMBEDDED_LAYOUT_PROMPT_FALLBACK = `You are an elite art director refining the layout and composition rules for a brand. This is ONLY about layout \u2014 structure, zones, grid, density, rhythm, containers, image placement, CTAs. Typography, colors, motion, animations, shadows are handled by separate brand files \u2014 do not duplicate them here.
|
|
40642
|
-
|
|
40643
|
-
These rules must work across media \u2014 web pages, print, PDF, presentations. Use proportional language (fractions, ratios, percentages) as the primary system. CSS values are welcome as concrete examples but should not be the only expression of a rule.
|
|
40644
|
-
|
|
40645
|
-
Your job: update the design role document based on the user's refinement prompt. This document will be injected wholesale into an AI builder's context. If your rules are vague, the output will be generic. If your rules are specific and opinionated, the output will be distinctive.
|
|
40646
|
-
|
|
40647
|
-
The document must be a complete markdown document covering:
|
|
40648
|
-
- Enemy (a specific design this must NOT resemble, with 2-3 specific layout patterns that make it wrong \u2014 and for each, the exact counter-pattern this brand uses instead)
|
|
40649
|
-
- Signature Anomaly (the one structural layout choice that makes this unmistakably distinctive)
|
|
40650
|
-
- Compositional Philosophy (one structural law + the structural spine mechanism that enforces it across every zone)
|
|
40651
|
-
- Intensity Dials (Density 1-10, Grid Variance 1-10 \u2014 with concrete implications for THIS brand)
|
|
40652
|
-
- Opening Zone / Hero Behavior (surface coverage, bleed, content placement, containment)
|
|
40653
|
-
- Zone Inventory (ordered list of all major zones: name, layout job, dense/airy, full-bleed/contained \u2014 this is the master reference for the rhythm)
|
|
40654
|
-
- Zone Variation & Flow (how zones differ, transition strategy, full-bleed vs contained \u2014 references the Zone Inventory)
|
|
40655
|
-
- Density Philosophy (spacing values; the oscillation rhythm derived from the Zone Inventory \u2014 name which zones are dense, which are airy, in sequence)
|
|
40656
|
-
- Vertical Rhythm (three values: zone padding, element gap within zones, and the one zone that breaks the rhythm and why)
|
|
40657
|
-
- Grid System (exact column structure, asymmetry, proportions)
|
|
40658
|
-
- Content Width Strategy (max-width of the primary content area, which zones break it and why)
|
|
40659
|
-
- Container & Card Rules (borders, corners, nesting, exact border-radius)
|
|
40660
|
-
- Dividers & Graphic Structure (structural vs decorative, background strategy)
|
|
40661
|
-
- Image Treatment \u2014 Layout Only (placement, grid relationship, overlap behavior)
|
|
40662
|
-
- CTA Strategy (position in layout referencing Zone Inventory, container strategy, frequency)
|
|
40663
|
-
- Responsive Behavior (how the layout adapts across sizes \u2014 web: breakpoints and stacking; print: scale and margin strategy)
|
|
40664
|
-
- Bans (at least 20 specific layout prohibitions)
|
|
40665
|
-
|
|
40666
|
-
## Critical rules
|
|
40667
|
-
|
|
40668
|
-
1. This is a REFINEMENT. The user already has a role document (shown below). Their prompt refines, evolves, or redirects \u2014 it does NOT start from scratch unless they explicitly say so.
|
|
40669
|
-
|
|
40670
|
-
2. SPECIFICITY IS MANDATORY. Every rule must be actionable at the structural level. Generic adjectives ("clean", "minimal", "modern", "elegant") are BANNED from the output.
|
|
40671
|
-
|
|
40672
|
-
3. THE DOCUMENT MUST BE OPINIONATED, NOT HEDGED. Every sentence must prescribe or ban \u2014 never suggest. Use "Always", "Never", "Must", "Banned", "Required".
|
|
40673
|
-
|
|
40674
|
-
4. STAY IN YOUR LANE. Do NOT include rules about typography, colors, motion/animation, or shadows \u2014 those belong in their own brand files.
|
|
40675
|
-
|
|
40676
|
-
5. THE BANS ARE THE MOST IMPORTANT SECTION. At least 20 bans. The 7 universal AI-layout cliches MUST each appear as an explicit named ban: centered headline over full-width image; three equal-width feature cards in a row; alternating left-right image/text rows with identical padding; uniform zone height and padding; every block wrapped in a card with shadow + radius; CTA with gradient fill; full-width "Why Choose Us" icon grid. Plus 3-5 brand-specific AI tells.
|
|
40677
|
-
|
|
40678
|
-
6. THE ENEMY IS MANDATORY. Name a specific real design and 2-3 exact layout patterns from it. Vague enemies fail.
|
|
40679
|
-
|
|
40680
|
-
7. THE SIGNATURE ANOMALY IS MANDATORY. One specific structural choice. Apply the removal test: if removing this single decision would make the layout indistinguishable from a generic design \u2014 it qualifies. Must appear as a constraint in at least 2 other sections.
|
|
40681
|
-
|
|
40682
|
-
8. USE THE STRUCTURAL CONTEXT. The {{structuralContext}} contains sibling brand files. Do not duplicate their rules \u2014 derive layout implications from them.
|
|
40683
|
-
|
|
40684
|
-
## Current role document
|
|
40685
|
-
|
|
40686
|
-
{{currentValues}}
|
|
40687
|
-
|
|
40688
|
-
## Structural context (sibling brand files)
|
|
40689
|
-
|
|
40690
|
-
{{structuralContext}}
|
|
40691
|
-
|
|
40692
|
-
## User's refinement prompt
|
|
40693
|
-
|
|
40694
|
-
{{userPrompt}}
|
|
40695
|
-
|
|
40696
|
-
## Response format
|
|
40697
|
-
|
|
40698
|
-
Return ONLY a JSON object: { "roleDocument": "# Brand Layout Role\\n\\n## Enemy\\n..." }
|
|
40699
|
-
|
|
40700
|
-
Output ONLY the JSON object. No markdown fences. No explanation.`;
|
|
40701
40761
|
function buildQaSystemPrompt(questions, layoutPromptSpec) {
|
|
40702
40762
|
return `You are a chill creative director doing a quick vibe check on someone's layout taste.
|
|
40703
40763
|
|
|
@@ -42619,9 +42679,35 @@ var Session = class _Session {
|
|
|
42619
42679
|
this.emit(message);
|
|
42620
42680
|
}
|
|
42621
42681
|
/**
|
|
42622
|
-
*
|
|
42682
|
+
* Push the first page of the agent directory unsolicited right after
|
|
42683
|
+
* `server_info` so the client can paint attention state before its own
|
|
42684
|
+
* paginated `fetch_agents_request` round-trip lands. The regular fetch
|
|
42685
|
+
* still runs in parallel — it establishes the live-update subscription
|
|
42686
|
+
* and paginates beyond the first page. This push exists purely to shave
|
|
42687
|
+
* one relay round-trip from time-to-first-paint.
|
|
42688
|
+
*
|
|
42689
|
+
* Errors are swallowed: a failed push degrades to "wait for the client
|
|
42690
|
+
* to ask," which is still correct.
|
|
42623
42691
|
*/
|
|
42624
42692
|
async sendInitialState() {
|
|
42693
|
+
try {
|
|
42694
|
+
const synthetic = {
|
|
42695
|
+
type: "fetch_agents_request",
|
|
42696
|
+
requestId: "internal:initial-snapshot",
|
|
42697
|
+
filter: { includeArchived: true },
|
|
42698
|
+
page: { limit: InitialAgentSnapshotPageLimit }
|
|
42699
|
+
};
|
|
42700
|
+
const { entries } = await this.listFetchAgentsEntries(synthetic);
|
|
42701
|
+
this.emit({
|
|
42702
|
+
type: "initial_agent_snapshot",
|
|
42703
|
+
payload: { entries }
|
|
42704
|
+
});
|
|
42705
|
+
} catch (error) {
|
|
42706
|
+
this.sessionLogger.warn(
|
|
42707
|
+
{ err: error },
|
|
42708
|
+
"Failed to push initial agent snapshot \u2014 client will fall back to fetch_agents_request"
|
|
42709
|
+
);
|
|
42710
|
+
}
|
|
42625
42711
|
}
|
|
42626
42712
|
/**
|
|
42627
42713
|
* Normalize a user prompt (with optional image metadata) for AgentManager
|
|
@@ -53017,6 +53103,7 @@ var VoiceAssistantWebSocketServer = class {
|
|
|
53017
53103
|
this.sessions.set(ws, connection);
|
|
53018
53104
|
this.externalSessionsByKey.set(clientId, connection);
|
|
53019
53105
|
this.sendToClient(ws, this.createServerInfoMessage());
|
|
53106
|
+
void connection.session.sendInitialState();
|
|
53020
53107
|
connection.connectionLogger.trace(
|
|
53021
53108
|
{
|
|
53022
53109
|
clientId,
|