@qloo/qloo-harness 0.1.18
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/LICENSE +21 -0
- package/README.md +394 -0
- package/THIRD_PARTY_NOTICES.md +40 -0
- package/dist/app.js +48 -0
- package/dist/bin.js +14 -0
- package/dist/build.js +117 -0
- package/dist/cli.js +95 -0
- package/dist/doctor.js +1019 -0
- package/dist/exec.js +782 -0
- package/dist/guided-journey.js +223 -0
- package/dist/index.d.ts +1321 -0
- package/dist/index.js +156 -0
- package/dist/integration-plan.js +1097 -0
- package/dist/mcp.js +909 -0
- package/dist/observability.js +115 -0
- package/dist/paths.js +77 -0
- package/dist/plan.js +163 -0
- package/dist/profiles.js +63 -0
- package/dist/project-context.js +364 -0
- package/dist/qloo-presentation.js +358 -0
- package/dist/qloo-tools.js +2195 -0
- package/dist/resolution-provider.js +1380 -0
- package/dist/router.js +6061 -0
- package/dist/runtime/explore-policy.js +666 -0
- package/dist/runtime/pi-adapter.js +259 -0
- package/dist/runtime/pi-command-policy.js +74 -0
- package/dist/runtime/qloo-header.js +173 -0
- package/dist/runtime/resources.js +37 -0
- package/dist/setup.js +1138 -0
- package/dist/update-manager.js +906 -0
- package/dist/workflow-executor.js +976 -0
- package/package.json +72 -0
- package/resources/BUILD.md +24 -0
- package/resources/EXPLORE.md +34 -0
- package/resources/INTEGRATE.md +28 -0
- package/resources/PLAN.md +23 -0
- package/resources/SYSTEM.md +49 -0
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
import { createRequire as __qlooCreateRequire } from "node:module";
|
|
2
|
+
const require = __qlooCreateRequire(import.meta.url);
|
|
3
|
+
|
|
4
|
+
// apps/qloo-harness/dist/runtime/pi-adapter.js
|
|
5
|
+
import { ensureQlooStateDirectories } from "../paths.js";
|
|
6
|
+
import { getQlooToolRuntimeInfo } from "../qloo-tools.js";
|
|
7
|
+
import { QLOO_DEFAULT_PROFILE } from "../profiles.js";
|
|
8
|
+
import { buildProfileToolNames, createHarnessPolicyExtension } from "./explore-policy.js";
|
|
9
|
+
import { applyPiInteractiveCommandPolicy, PINNED_PI_VERSION } from "./pi-command-policy.js";
|
|
10
|
+
import { instructionsForProfile } from "./resources.js";
|
|
11
|
+
var PI_AGENT_DIR_ENVIRONMENT_VARIABLE = "PI_CODING_AGENT_DIR";
|
|
12
|
+
var PI_TELEMETRY_ENVIRONMENT_VARIABLE = "PI_TELEMETRY";
|
|
13
|
+
var PI_SKIP_VERSION_CHECK_ENVIRONMENT_VARIABLE = "PI_SKIP_VERSION_CHECK";
|
|
14
|
+
var PI_OFFLINE_ENVIRONMENT_VARIABLE = "PI_OFFLINE";
|
|
15
|
+
var QLOO_MODEL_RETRY_POLICY = Object.freeze({
|
|
16
|
+
maxRetries: 1,
|
|
17
|
+
baseDelayMs: 1e3,
|
|
18
|
+
providerTimeoutMs: 6e4,
|
|
19
|
+
providerMaxRetries: 0,
|
|
20
|
+
providerMaxRetryDelayMs: 5e3
|
|
21
|
+
});
|
|
22
|
+
var PI_PRIVACY_DEFAULTS = {
|
|
23
|
+
[PI_TELEMETRY_ENVIRONMENT_VARIABLE]: "0",
|
|
24
|
+
[PI_SKIP_VERSION_CHECK_ENVIRONMENT_VARIABLE]: "1",
|
|
25
|
+
[PI_OFFLINE_ENVIRONMENT_VARIABLE]: "1"
|
|
26
|
+
};
|
|
27
|
+
function applyQlooModelRetryPolicy(settingsManager) {
|
|
28
|
+
const configured = settingsManager.getGlobalSettings().retry;
|
|
29
|
+
const provider = configured?.provider;
|
|
30
|
+
settingsManager.applyOverrides({
|
|
31
|
+
retry: {
|
|
32
|
+
enabled: configured?.enabled ?? true,
|
|
33
|
+
maxRetries: Math.min(configured?.maxRetries ?? QLOO_MODEL_RETRY_POLICY.maxRetries, QLOO_MODEL_RETRY_POLICY.maxRetries),
|
|
34
|
+
baseDelayMs: Math.min(configured?.baseDelayMs ?? QLOO_MODEL_RETRY_POLICY.baseDelayMs, 2e3),
|
|
35
|
+
provider: {
|
|
36
|
+
timeoutMs: Math.min(provider?.timeoutMs ?? QLOO_MODEL_RETRY_POLICY.providerTimeoutMs, 12e4),
|
|
37
|
+
maxRetries: QLOO_MODEL_RETRY_POLICY.providerMaxRetries,
|
|
38
|
+
maxRetryDelayMs: Math.min(provider?.maxRetryDelayMs ?? QLOO_MODEL_RETRY_POLICY.providerMaxRetryDelayMs, QLOO_MODEL_RETRY_POLICY.providerMaxRetryDelayMs)
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
async function withEnvironmentVariable(name, value, operation) {
|
|
44
|
+
const hadPreviousValue = Object.hasOwn(process.env, name);
|
|
45
|
+
const previousValue = process.env[name];
|
|
46
|
+
process.env[name] = value;
|
|
47
|
+
try {
|
|
48
|
+
return await operation();
|
|
49
|
+
} finally {
|
|
50
|
+
if (hadPreviousValue) {
|
|
51
|
+
process.env[name] = previousValue;
|
|
52
|
+
} else {
|
|
53
|
+
delete process.env[name];
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
async function withPiAgentDirectory(agentDir, operation) {
|
|
58
|
+
return withEnvironmentVariable(PI_AGENT_DIR_ENVIRONMENT_VARIABLE, agentDir, operation);
|
|
59
|
+
}
|
|
60
|
+
async function withPiPrivacyDefaults(operation) {
|
|
61
|
+
const previous = Object.entries(PI_PRIVACY_DEFAULTS).map(([name, defaultValue]) => ({
|
|
62
|
+
name,
|
|
63
|
+
defaultValue,
|
|
64
|
+
existed: Object.hasOwn(process.env, name),
|
|
65
|
+
value: process.env[name]
|
|
66
|
+
}));
|
|
67
|
+
for (const entry of previous) {
|
|
68
|
+
if (!entry.existed)
|
|
69
|
+
process.env[entry.name] = entry.defaultValue;
|
|
70
|
+
}
|
|
71
|
+
try {
|
|
72
|
+
return await operation();
|
|
73
|
+
} finally {
|
|
74
|
+
for (const entry of previous) {
|
|
75
|
+
if (entry.existed)
|
|
76
|
+
process.env[entry.name] = entry.value;
|
|
77
|
+
else
|
|
78
|
+
delete process.env[entry.name];
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
var MissingModelAuthenticationError = class extends Error {
|
|
83
|
+
authFile;
|
|
84
|
+
constructor(authFile) {
|
|
85
|
+
super([
|
|
86
|
+
"No authenticated model provider is available for Qloo.",
|
|
87
|
+
"Run `qloo setup --model` to sign in to a supported provider, then rerun `qloo`.",
|
|
88
|
+
`Provider state is stored in the Pi ${PINNED_PI_VERSION}-compatible Qloo auth file at ${authFile};`,
|
|
89
|
+
"use `qloo doctor` to validate it before starting chat."
|
|
90
|
+
].join(" "));
|
|
91
|
+
this.name = "MissingModelAuthenticationError";
|
|
92
|
+
this.authFile = authFile;
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
async function requireAuthenticatedModel(modelRuntime, authFile) {
|
|
96
|
+
const availableModels = await modelRuntime.getAvailable();
|
|
97
|
+
if (availableModels.length === 0) {
|
|
98
|
+
throw new MissingModelAuthenticationError(authFile);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
function buildExploreResourceOptions(resources, allowedToolNames) {
|
|
102
|
+
return buildHarnessResourceOptions(resources, allowedToolNames, "explore");
|
|
103
|
+
}
|
|
104
|
+
function buildHarnessResourceOptions(resources, allowedToolNames, profile, runtimeInfo, commandActions) {
|
|
105
|
+
return {
|
|
106
|
+
noExtensions: true,
|
|
107
|
+
noSkills: true,
|
|
108
|
+
noPromptTemplates: true,
|
|
109
|
+
noThemes: true,
|
|
110
|
+
noContextFiles: true,
|
|
111
|
+
extensionFactories: [createHarnessPolicyExtension(profile, allowedToolNames, runtimeInfo, commandActions)],
|
|
112
|
+
agentsFilesOverride: () => ({ agentsFiles: [] }),
|
|
113
|
+
systemPromptOverride: () => resources.systemPrompt,
|
|
114
|
+
appendSystemPromptOverride: () => [instructionsForProfile(resources, profile)]
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
var PiHarnessRuntime = class {
|
|
118
|
+
sessionRuntime;
|
|
119
|
+
runStarted = false;
|
|
120
|
+
disposed = false;
|
|
121
|
+
constructor(sessionRuntime) {
|
|
122
|
+
this.sessionRuntime = sessionRuntime;
|
|
123
|
+
}
|
|
124
|
+
/** Run one model turn through the same session, tools, and policy as the TUI. */
|
|
125
|
+
async runPrompt(prompt) {
|
|
126
|
+
if (this.disposed) {
|
|
127
|
+
throw new Error("Qloo runtime has already been disposed");
|
|
128
|
+
}
|
|
129
|
+
if (this.runStarted) {
|
|
130
|
+
throw new Error("Qloo runtime can only be started once");
|
|
131
|
+
}
|
|
132
|
+
this.runStarted = true;
|
|
133
|
+
return withPiAgentDirectory(this.sessionRuntime.services.agentDir, () => withPiPrivacyDefaults(async () => {
|
|
134
|
+
await this.sessionRuntime.session.prompt(prompt, {
|
|
135
|
+
expandPromptTemplates: false,
|
|
136
|
+
source: "rpc"
|
|
137
|
+
});
|
|
138
|
+
await this.sessionRuntime.session.waitForIdle();
|
|
139
|
+
return this.sessionRuntime.session.getLastAssistantText();
|
|
140
|
+
}));
|
|
141
|
+
}
|
|
142
|
+
async runInteractive(options = {}) {
|
|
143
|
+
if (this.disposed) {
|
|
144
|
+
throw new Error("Qloo runtime has already been disposed");
|
|
145
|
+
}
|
|
146
|
+
if (this.runStarted) {
|
|
147
|
+
throw new Error("Qloo interactive mode can only be started once");
|
|
148
|
+
}
|
|
149
|
+
this.runStarted = true;
|
|
150
|
+
const interactiveOptions = {
|
|
151
|
+
migratedProviders: [],
|
|
152
|
+
initialImages: [],
|
|
153
|
+
initialMessages: [],
|
|
154
|
+
...options
|
|
155
|
+
};
|
|
156
|
+
if (interactiveOptions.modelFallbackMessage === void 0 && this.sessionRuntime.modelFallbackMessage !== void 0) {
|
|
157
|
+
interactiveOptions.modelFallbackMessage = this.sessionRuntime.modelFallbackMessage;
|
|
158
|
+
}
|
|
159
|
+
await withPiAgentDirectory(this.sessionRuntime.services.agentDir, () => withPiPrivacyDefaults(async () => {
|
|
160
|
+
const { InteractiveMode } = await import("@earendil-works/pi-coding-agent");
|
|
161
|
+
const mode = new InteractiveMode(this.sessionRuntime, interactiveOptions);
|
|
162
|
+
applyPiInteractiveCommandPolicy(mode);
|
|
163
|
+
await mode.run();
|
|
164
|
+
}));
|
|
165
|
+
}
|
|
166
|
+
async dispose() {
|
|
167
|
+
if (this.disposed) {
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
this.disposed = true;
|
|
171
|
+
await this.sessionRuntime.dispose();
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
async function createPiHarnessRuntime(options) {
|
|
175
|
+
const customTools = [...options.customTools ?? []];
|
|
176
|
+
const profile = options.profile ?? QLOO_DEFAULT_PROFILE;
|
|
177
|
+
const activeToolNames = buildProfileToolNames(profile, customTools);
|
|
178
|
+
const toolByName = new Map(customTools.map((tool) => [tool.name, tool]));
|
|
179
|
+
const interactiveCommandActions = {
|
|
180
|
+
...options.interactiveCommandActions ?? {},
|
|
181
|
+
async retry(toolName, input) {
|
|
182
|
+
const tool = toolByName.get(toolName);
|
|
183
|
+
if (!tool || !toolName.startsWith("qloo_") || toolName === "qloo_capabilities") {
|
|
184
|
+
throw new Error(`No replayable Qloo tool is registered as ${toolName}.`);
|
|
185
|
+
}
|
|
186
|
+
const result = await tool.execute(`qloo-retry-${Date.now().toString(36)}`, input, AbortSignal.timeout(3e4), void 0, {});
|
|
187
|
+
if (result.details === null || typeof result.details !== "object" || Array.isArray(result.details)) {
|
|
188
|
+
throw new Error(`${toolName} returned no structured details.`);
|
|
189
|
+
}
|
|
190
|
+
return result.details;
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
await ensureQlooStateDirectories(options.paths);
|
|
194
|
+
return withPiAgentDirectory(options.paths.agentDir, () => withPiPrivacyDefaults(async () => {
|
|
195
|
+
const { ModelRuntime, SessionManager, SettingsManager, createAgentSessionFromServices, createAgentSessionRuntime, createAgentSessionServices } = await import("@earendil-works/pi-coding-agent");
|
|
196
|
+
const allowedToolNames = new Set(activeToolNames);
|
|
197
|
+
const modelRuntime = options.modelRuntime ?? await ModelRuntime.create({
|
|
198
|
+
authPath: options.paths.authFile,
|
|
199
|
+
modelsPath: options.paths.modelsFile,
|
|
200
|
+
modelsStorePath: options.paths.modelsStoreFile,
|
|
201
|
+
allowModelNetwork: false
|
|
202
|
+
});
|
|
203
|
+
const createRuntime = async ({ cwd, sessionManager: sessionManager2, sessionStartEvent }) => {
|
|
204
|
+
const settingsManager = SettingsManager.create(cwd, options.paths.agentDir, {
|
|
205
|
+
projectTrusted: false
|
|
206
|
+
});
|
|
207
|
+
applyQlooModelRetryPolicy(settingsManager);
|
|
208
|
+
const services = await createAgentSessionServices({
|
|
209
|
+
cwd,
|
|
210
|
+
agentDir: options.paths.agentDir,
|
|
211
|
+
settingsManager,
|
|
212
|
+
modelRuntime,
|
|
213
|
+
resourceLoaderOptions: buildHarnessResourceOptions(options.resources, allowedToolNames, profile, getQlooToolRuntimeInfo(customTools), interactiveCommandActions)
|
|
214
|
+
});
|
|
215
|
+
await requireAuthenticatedModel(services.modelRuntime, options.paths.authFile);
|
|
216
|
+
for (const settingsError of settingsManager.drainErrors()) {
|
|
217
|
+
services.diagnostics.push({
|
|
218
|
+
type: "warning",
|
|
219
|
+
message: `Could not load Qloo ${settingsError.scope} settings: ${settingsError.error.message}`
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
const sessionOptions = {
|
|
223
|
+
services,
|
|
224
|
+
sessionManager: sessionManager2,
|
|
225
|
+
tools: activeToolNames,
|
|
226
|
+
customTools,
|
|
227
|
+
...sessionStartEvent === void 0 ? {} : { sessionStartEvent }
|
|
228
|
+
};
|
|
229
|
+
return {
|
|
230
|
+
...await createAgentSessionFromServices(sessionOptions),
|
|
231
|
+
services,
|
|
232
|
+
diagnostics: services.diagnostics
|
|
233
|
+
};
|
|
234
|
+
};
|
|
235
|
+
const sessionManager = options.sessionManager ?? SessionManager.create(options.cwd, options.paths.sessionDir);
|
|
236
|
+
const sessionRuntime = await createAgentSessionRuntime(createRuntime, {
|
|
237
|
+
cwd: options.cwd,
|
|
238
|
+
agentDir: options.paths.agentDir,
|
|
239
|
+
sessionManager
|
|
240
|
+
});
|
|
241
|
+
return new PiHarnessRuntime(sessionRuntime);
|
|
242
|
+
}));
|
|
243
|
+
}
|
|
244
|
+
export {
|
|
245
|
+
MissingModelAuthenticationError,
|
|
246
|
+
PI_AGENT_DIR_ENVIRONMENT_VARIABLE,
|
|
247
|
+
PI_OFFLINE_ENVIRONMENT_VARIABLE,
|
|
248
|
+
PI_SKIP_VERSION_CHECK_ENVIRONMENT_VARIABLE,
|
|
249
|
+
PI_TELEMETRY_ENVIRONMENT_VARIABLE,
|
|
250
|
+
PiHarnessRuntime,
|
|
251
|
+
QLOO_MODEL_RETRY_POLICY,
|
|
252
|
+
applyQlooModelRetryPolicy,
|
|
253
|
+
buildExploreResourceOptions,
|
|
254
|
+
buildHarnessResourceOptions,
|
|
255
|
+
createPiHarnessRuntime,
|
|
256
|
+
requireAuthenticatedModel,
|
|
257
|
+
withPiAgentDirectory,
|
|
258
|
+
withPiPrivacyDefaults
|
|
259
|
+
};
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { createRequire as __qlooCreateRequire } from "node:module";
|
|
2
|
+
const require = __qlooCreateRequire(import.meta.url);
|
|
3
|
+
|
|
4
|
+
// apps/qloo-harness/dist/runtime/pi-command-policy.js
|
|
5
|
+
var PINNED_PI_VERSION = "0.84.2";
|
|
6
|
+
var BLOCKED_PI_INTERACTIVE_COMMANDS = /* @__PURE__ */ new Set(["share", "trust"]);
|
|
7
|
+
var PI_SHARE_BLOCK_MESSAGE = "External session sharing is disabled in the Qloo harness.";
|
|
8
|
+
var PI_TRUST_BLOCK_MESSAGE = "Project trust changes are disabled in Qloo's explore profile.";
|
|
9
|
+
var PI_SUPPRESSED_OFFLINE_MANAGED_TOOL_WARNINGS = /* @__PURE__ */ new Set([
|
|
10
|
+
"fd not found. Offline mode enabled, skipping download.",
|
|
11
|
+
"ripgrep not found. Offline mode enabled, skipping download."
|
|
12
|
+
]);
|
|
13
|
+
var REQUIRED_PI_INTERNAL_METHODS = [
|
|
14
|
+
"handleShareCommand",
|
|
15
|
+
"showTrustSelector",
|
|
16
|
+
"showError",
|
|
17
|
+
"showManagedToolStatus"
|
|
18
|
+
];
|
|
19
|
+
var PiCommandPolicyCompatibilityError = class extends Error {
|
|
20
|
+
constructor(method) {
|
|
21
|
+
super(`Qloo cannot safely start with Pi ${PINNED_PI_VERSION}: required interactive policy seam "${method}" is unavailable.`);
|
|
22
|
+
this.name = "PiCommandPolicyCompatibilityError";
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
function isBlockedPiInteractiveCommand(value) {
|
|
26
|
+
const firstToken = value.trim().split(/\s+/u, 1)[0] ?? "";
|
|
27
|
+
const command = firstToken.replace(/^\/+/, "");
|
|
28
|
+
return BLOCKED_PI_INTERACTIVE_COMMANDS.has(command);
|
|
29
|
+
}
|
|
30
|
+
function applyPiInteractiveCommandPolicy(mode) {
|
|
31
|
+
const internals = mode;
|
|
32
|
+
for (const method of REQUIRED_PI_INTERNAL_METHODS) {
|
|
33
|
+
if (typeof internals[method] !== "function") {
|
|
34
|
+
throw new PiCommandPolicyCompatibilityError(method);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
const showError = internals.showError.bind(mode);
|
|
38
|
+
const showManagedToolStatus = internals.showManagedToolStatus.bind(mode);
|
|
39
|
+
Object.defineProperties(internals, {
|
|
40
|
+
handleShareCommand: {
|
|
41
|
+
configurable: false,
|
|
42
|
+
enumerable: false,
|
|
43
|
+
writable: false,
|
|
44
|
+
value: async () => showError(PI_SHARE_BLOCK_MESSAGE)
|
|
45
|
+
},
|
|
46
|
+
showTrustSelector: {
|
|
47
|
+
configurable: false,
|
|
48
|
+
enumerable: false,
|
|
49
|
+
writable: false,
|
|
50
|
+
value: () => showError(PI_TRUST_BLOCK_MESSAGE)
|
|
51
|
+
},
|
|
52
|
+
showManagedToolStatus: {
|
|
53
|
+
configurable: false,
|
|
54
|
+
enumerable: false,
|
|
55
|
+
writable: false,
|
|
56
|
+
value: (status) => {
|
|
57
|
+
if (status.type === "warning" && PI_SUPPRESSED_OFFLINE_MANAGED_TOOL_WARNINGS.has(status.message)) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
showManagedToolStatus(status);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
export {
|
|
66
|
+
BLOCKED_PI_INTERACTIVE_COMMANDS,
|
|
67
|
+
PINNED_PI_VERSION,
|
|
68
|
+
PI_SHARE_BLOCK_MESSAGE,
|
|
69
|
+
PI_SUPPRESSED_OFFLINE_MANAGED_TOOL_WARNINGS,
|
|
70
|
+
PI_TRUST_BLOCK_MESSAGE,
|
|
71
|
+
PiCommandPolicyCompatibilityError,
|
|
72
|
+
applyPiInteractiveCommandPolicy,
|
|
73
|
+
isBlockedPiInteractiveCommand
|
|
74
|
+
};
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { createRequire as __qlooCreateRequire } from "node:module";
|
|
2
|
+
const require = __qlooCreateRequire(import.meta.url);
|
|
3
|
+
|
|
4
|
+
// apps/qloo-harness/dist/runtime/qloo-header.js
|
|
5
|
+
var QLOO_LOGO_WIDTH = 39;
|
|
6
|
+
var QLOO_LOGO_ART = [
|
|
7
|
+
" \u256D\u2500\u2500\u2500\u2500\u256E\u2577 \u256D\u2500\u2500\u2500\u256E \u256D\u2500\u2500\u2500\u256E ",
|
|
8
|
+
" \u25CF\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2502 \u2502\u2502 \u2502 \u251C\u2500\u2524 \u2502\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u25CF ",
|
|
9
|
+
" \u2570\u2500\u2500\u252C\u2500\u256F\u2570\u2500\u2570\u2500\u2500\u2500\u256F \u2570\u2500\u2500\u2500\u256F ",
|
|
10
|
+
" \u2570\u2574 "
|
|
11
|
+
];
|
|
12
|
+
var QLOO_MEDIUM_LOGO_WIDTH = 57;
|
|
13
|
+
var QLOO_MEDIUM_LOGO_ART = [
|
|
14
|
+
"\u256D\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E \u2577 \u256D\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E \u256D\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E",
|
|
15
|
+
"\u2502 \u2502 \u2502 \u2502 \u2502 \u2502 \u2502",
|
|
16
|
+
"\u2502 \u2502 \u2502 \u2502 \u2502 \u2502 \u2502",
|
|
17
|
+
"\u2502 \u2502 \u2502 \u2502 \u251C\u2500\u2500\u2500\u2524 \u2502",
|
|
18
|
+
"\u2502 \u2502 \u2502 \u2502 \u2502 \u2502 \u2502",
|
|
19
|
+
"\u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F \u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 \u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F \u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F",
|
|
20
|
+
" \u2570\u2500\u2500\u2574"
|
|
21
|
+
];
|
|
22
|
+
var QLOO_HERO_LOGO_WIDTH = 86;
|
|
23
|
+
var QLOO_HERO_LOGO_ART = [
|
|
24
|
+
"\u256D\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E \u2577 \u256D\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E \u256D\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E",
|
|
25
|
+
"\u2502 \u2502 \u2502 \u2502 \u2502 \u2502 \u2502",
|
|
26
|
+
"\u2502 \u2502 \u2502 \u2502 \u2502 \u2502 \u2502",
|
|
27
|
+
"\u2502 \u2502 \u2502 \u2502 \u251C\u2500\u2500\u2500\u2500\u2524 \u2502",
|
|
28
|
+
"\u2502 \u2502 \u2502 \u2502 \u2502 \u2502 \u2502",
|
|
29
|
+
"\u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F \u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 \u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F \u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F",
|
|
30
|
+
" \u2570\u2500\u2500\u2500\u2500\u2574"
|
|
31
|
+
];
|
|
32
|
+
var QLOO_MEDIUM_MIN_TERMINAL_WIDTH = QLOO_MEDIUM_LOGO_WIDTH + 4;
|
|
33
|
+
var QLOO_HERO_MIN_TERMINAL_WIDTH = QLOO_HERO_LOGO_WIDTH + 4;
|
|
34
|
+
var QLOO_HERO_MAX_BANNER_WIDTH = 160;
|
|
35
|
+
var QLOO_HEADER_TAGLINE = "how AI understands taste";
|
|
36
|
+
var QLOO_BRAND_GRADIENT = [
|
|
37
|
+
{ red: 93, green: 37, blue: 182 },
|
|
38
|
+
{ red: 57, green: 62, blue: 195 },
|
|
39
|
+
{ red: 16, green: 89, blue: 205 }
|
|
40
|
+
];
|
|
41
|
+
function interpolateChannel(start, end, amount) {
|
|
42
|
+
return Math.round(start + (end - start) * amount);
|
|
43
|
+
}
|
|
44
|
+
function interpolateColor(start, end, amount) {
|
|
45
|
+
return {
|
|
46
|
+
red: interpolateChannel(start.red, end.red, amount),
|
|
47
|
+
green: interpolateChannel(start.green, end.green, amount),
|
|
48
|
+
blue: interpolateChannel(start.blue, end.blue, amount)
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
function gradientColor(index, length) {
|
|
52
|
+
const progress = length <= 1 ? 0 : index / (length - 1);
|
|
53
|
+
if (progress <= 0.5) {
|
|
54
|
+
return interpolateColor(QLOO_BRAND_GRADIENT[0], QLOO_BRAND_GRADIENT[1], progress * 2);
|
|
55
|
+
}
|
|
56
|
+
return interpolateColor(QLOO_BRAND_GRADIENT[1], QLOO_BRAND_GRADIENT[2], (progress - 0.5) * 2);
|
|
57
|
+
}
|
|
58
|
+
function ansi256(color) {
|
|
59
|
+
const red = Math.round(color.red / 255 * 5);
|
|
60
|
+
const green = Math.round(color.green / 255 * 5);
|
|
61
|
+
const blue = Math.round(color.blue / 255 * 5);
|
|
62
|
+
return 16 + 36 * red + 6 * green + blue;
|
|
63
|
+
}
|
|
64
|
+
function foreground(color, mode) {
|
|
65
|
+
if (mode === "truecolor") {
|
|
66
|
+
return `\x1B[38;2;${color.red};${color.green};${color.blue}m`;
|
|
67
|
+
}
|
|
68
|
+
return `\x1B[38;5;${ansi256(color)}m`;
|
|
69
|
+
}
|
|
70
|
+
function background(color, mode) {
|
|
71
|
+
if (mode === "truecolor") {
|
|
72
|
+
return `\x1B[48;2;${color.red};${color.green};${color.blue}m`;
|
|
73
|
+
}
|
|
74
|
+
return `\x1B[48;5;${ansi256(color)}m`;
|
|
75
|
+
}
|
|
76
|
+
function renderLogoLine(line, mode) {
|
|
77
|
+
const characters = [...line];
|
|
78
|
+
const white = mode === "truecolor" ? "\x1B[38;2;255;255;255m" : "\x1B[38;5;15m";
|
|
79
|
+
const painted = characters.map((character, index) => `${background(gradientColor(index, characters.length), mode)}${character}`).join("");
|
|
80
|
+
return `${white}${painted}\x1B[39;49m`;
|
|
81
|
+
}
|
|
82
|
+
function renderCenteredLogoLine(line, width, mode) {
|
|
83
|
+
const padding = Math.max(0, Math.floor((width - [...line].length) / 2));
|
|
84
|
+
return `${" ".repeat(padding)}${renderLogoLine(line, mode)}`;
|
|
85
|
+
}
|
|
86
|
+
function expandLogoArt(art, coreWidth, availableWidth, railRow) {
|
|
87
|
+
const bannerWidth = Math.min(availableWidth - 2, QLOO_HERO_MAX_BANNER_WIDTH);
|
|
88
|
+
const railSpace = bannerWidth - coreWidth - 2;
|
|
89
|
+
const left = Math.floor(railSpace / 2);
|
|
90
|
+
const right = railSpace - left;
|
|
91
|
+
return art.map((source, index) => {
|
|
92
|
+
const line = source.padEnd(coreWidth);
|
|
93
|
+
if (index === railRow) {
|
|
94
|
+
return `\u25CF${"\u2500".repeat(left)}${line}${"\u2500".repeat(right)}\u25CF`;
|
|
95
|
+
}
|
|
96
|
+
return `${" ".repeat(left + 1)}${line}${" ".repeat(right + 1)}`;
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
function renderBrandWord(word, mode) {
|
|
100
|
+
const characters = [...word];
|
|
101
|
+
const painted = characters.map((character, index) => `${foreground(gradientColor(index, characters.length), mode)}${character}`).join("");
|
|
102
|
+
return `${painted}\x1B[39m`;
|
|
103
|
+
}
|
|
104
|
+
function clip(text, width) {
|
|
105
|
+
const characters = [...text];
|
|
106
|
+
if (characters.length <= width)
|
|
107
|
+
return text;
|
|
108
|
+
if (width <= 0)
|
|
109
|
+
return "";
|
|
110
|
+
if (width === 1)
|
|
111
|
+
return "\u2026";
|
|
112
|
+
return `${characters.slice(0, width - 1).join("")}\u2026`;
|
|
113
|
+
}
|
|
114
|
+
function centered(text, width) {
|
|
115
|
+
const padding = Math.max(0, Math.floor((width - [...text].length) / 2));
|
|
116
|
+
return `${" ".repeat(padding)}${text}`;
|
|
117
|
+
}
|
|
118
|
+
function instructionForWidth(width, profile) {
|
|
119
|
+
const authority = {
|
|
120
|
+
explore: "Qloo + read-only files",
|
|
121
|
+
integrate: "Qloo + files + approved shell",
|
|
122
|
+
plan: "Qloo + read-only files",
|
|
123
|
+
build: "Qloo + approved shell/writes"
|
|
124
|
+
}[profile];
|
|
125
|
+
if (width >= 76) {
|
|
126
|
+
return `${profile} \xB7 ${authority} \xB7 /start guided help \xB7 ctrl+c/ctrl+d clear/exit`;
|
|
127
|
+
}
|
|
128
|
+
if (width >= 44)
|
|
129
|
+
return `${profile} \xB7 ${authority} \xB7 /start`;
|
|
130
|
+
return `${profile} \xB7 ${authority}`;
|
|
131
|
+
}
|
|
132
|
+
function promptForWidth(width, profile) {
|
|
133
|
+
const prompt = {
|
|
134
|
+
explore: "Ask Qloo about an audience, entity, place, trend, or recommendation.",
|
|
135
|
+
integrate: "Describe your system and the Qloo integration you want to design.",
|
|
136
|
+
plan: "Ask for a project-grounded Qloo implementation plan.",
|
|
137
|
+
build: "Describe the approved Qloo integration work to implement and verify."
|
|
138
|
+
}[profile];
|
|
139
|
+
if (width >= 38)
|
|
140
|
+
return prompt;
|
|
141
|
+
return profile === "explore" ? "Ask Qloo anything." : `${profile} with Qloo.`;
|
|
142
|
+
}
|
|
143
|
+
function renderQlooHeader(theme, availableWidth, profile = "explore") {
|
|
144
|
+
const width = Math.max(1, Math.floor(availableWidth));
|
|
145
|
+
const mode = theme.getColorMode();
|
|
146
|
+
const heroLogo = width >= QLOO_HERO_MIN_TERMINAL_WIDTH;
|
|
147
|
+
const mediumLogo = !heroLogo && width >= QLOO_MEDIUM_MIN_TERMINAL_WIDTH;
|
|
148
|
+
const compactLogo = !heroLogo && !mediumLogo && width >= QLOO_LOGO_WIDTH;
|
|
149
|
+
const expandedArt = heroLogo ? expandLogoArt(QLOO_HERO_LOGO_ART, QLOO_HERO_LOGO_WIDTH, width, 3) : mediumLogo ? expandLogoArt(QLOO_MEDIUM_LOGO_ART, QLOO_MEDIUM_LOGO_WIDTH, width, 3) : void 0;
|
|
150
|
+
const logo = expandedArt ? expandedArt.map((line) => renderCenteredLogoLine(line, width, mode)) : compactLogo ? QLOO_LOGO_ART.map((line) => renderCenteredLogoLine(line, width, mode)) : [theme.bold(renderBrandWord(centered(clip("Qloo", width), width), mode))];
|
|
151
|
+
const fullLogo = heroLogo || mediumLogo || compactLogo;
|
|
152
|
+
const taglineText = centered(clip(QLOO_HEADER_TAGLINE, width), width);
|
|
153
|
+
const tagline = fullLogo ? theme.bold(renderBrandWord(taglineText, mode)) : theme.fg("muted", taglineText);
|
|
154
|
+
return [
|
|
155
|
+
"",
|
|
156
|
+
...logo,
|
|
157
|
+
...heroLogo || mediumLogo ? [""] : [],
|
|
158
|
+
tagline,
|
|
159
|
+
theme.fg("muted", centered(clip(instructionForWidth(width, profile), width), width)),
|
|
160
|
+
theme.fg("dim", centered(clip(promptForWidth(width, profile), width), width)),
|
|
161
|
+
""
|
|
162
|
+
];
|
|
163
|
+
}
|
|
164
|
+
export {
|
|
165
|
+
QLOO_HEADER_TAGLINE,
|
|
166
|
+
QLOO_HERO_LOGO_ART,
|
|
167
|
+
QLOO_HERO_LOGO_WIDTH,
|
|
168
|
+
QLOO_LOGO_ART,
|
|
169
|
+
QLOO_LOGO_WIDTH,
|
|
170
|
+
QLOO_MEDIUM_LOGO_ART,
|
|
171
|
+
QLOO_MEDIUM_LOGO_WIDTH,
|
|
172
|
+
renderQlooHeader
|
|
173
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { createRequire as __qlooCreateRequire } from "node:module";
|
|
2
|
+
const require = __qlooCreateRequire(import.meta.url);
|
|
3
|
+
|
|
4
|
+
// apps/qloo-harness/dist/runtime/resources.js
|
|
5
|
+
import { readFile } from "node:fs/promises";
|
|
6
|
+
import { QLOO_HARNESS_PROFILES } from "../profiles.js";
|
|
7
|
+
var defaultResourceRoot = new URL("../../resources/", import.meta.url);
|
|
8
|
+
function normalizeResource(name, content) {
|
|
9
|
+
const normalized = content.replace(/^\uFEFF/, "").trim();
|
|
10
|
+
if (normalized.length === 0) {
|
|
11
|
+
throw new Error(`Bundled Qloo resource is empty: ${name}`);
|
|
12
|
+
}
|
|
13
|
+
return normalized;
|
|
14
|
+
}
|
|
15
|
+
async function loadHarnessResources(options = {}) {
|
|
16
|
+
const resourceRoot = options.resourceRoot ?? defaultResourceRoot;
|
|
17
|
+
const readText = options.readText ?? ((url) => readFile(url, "utf8"));
|
|
18
|
+
const systemUrl = new URL("SYSTEM.md", resourceRoot);
|
|
19
|
+
const profileEntries = await Promise.all(QLOO_HARNESS_PROFILES.map(async (profile) => {
|
|
20
|
+
const name = `${profile.toUpperCase()}.md`;
|
|
21
|
+
return [profile, normalizeResource(name, await readText(new URL(name, resourceRoot)))];
|
|
22
|
+
}));
|
|
23
|
+
const systemPrompt = await readText(systemUrl);
|
|
24
|
+
const profileInstructions = Object.fromEntries(profileEntries);
|
|
25
|
+
return {
|
|
26
|
+
systemPrompt: normalizeResource("SYSTEM.md", systemPrompt),
|
|
27
|
+
exploreInstructions: profileInstructions.explore,
|
|
28
|
+
profileInstructions
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
function instructionsForProfile(resources, profile) {
|
|
32
|
+
return resources.profileInstructions?.[profile] ?? resources.exploreInstructions;
|
|
33
|
+
}
|
|
34
|
+
export {
|
|
35
|
+
instructionsForProfile,
|
|
36
|
+
loadHarnessResources
|
|
37
|
+
};
|