spacecode 2.8.1 → 2.9.0
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/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/repl.mjs +431 -119
- package/package.json +1 -1
package/dist/repl.mjs
CHANGED
|
@@ -3825,50 +3825,193 @@ var init_bash = __esm({
|
|
|
3825
3825
|
}
|
|
3826
3826
|
});
|
|
3827
3827
|
|
|
3828
|
-
// ../
|
|
3829
|
-
|
|
3830
|
-
|
|
3831
|
-
|
|
3832
|
-
|
|
3833
|
-
|
|
3834
|
-
|
|
3835
|
-
|
|
3836
|
-
|
|
3837
|
-
|
|
3838
|
-
|
|
3839
|
-
|
|
3840
|
-
|
|
3841
|
-
|
|
3842
|
-
|
|
3843
|
-
|
|
3844
|
-
|
|
3845
|
-
|
|
3846
|
-
|
|
3847
|
-
|
|
3828
|
+
// ../shared/src/prompts/defaults-core.ts
|
|
3829
|
+
var DEFAULT_PROMPT_LIST;
|
|
3830
|
+
var init_defaults_core = __esm({
|
|
3831
|
+
"../shared/src/prompts/defaults-core.ts"() {
|
|
3832
|
+
"use strict";
|
|
3833
|
+
DEFAULT_PROMPT_LIST = [
|
|
3834
|
+
{
|
|
3835
|
+
key: "pipeline.decompose.system",
|
|
3836
|
+
description: "Splits a request into sub-tasks and enhances each (pipeline decomposer).",
|
|
3837
|
+
vars: [],
|
|
3838
|
+
body: `You are a task decomposition and prompt enhancement engine.
|
|
3839
|
+
|
|
3840
|
+
## Decomposition Rules
|
|
3841
|
+
Analyze user requests and determine if they contain multiple independent tasks.
|
|
3842
|
+
- Numbered lists, bullet points, or requests joined by "and"/"also" are decomposable
|
|
3843
|
+
- Each sub-task should be independently executable
|
|
3844
|
+
|
|
3845
|
+
## Prompt Enhancement Principles (MiniMax Best Practices)
|
|
3846
|
+
|
|
3847
|
+
1. **Be Specific and Detailed**
|
|
3848
|
+
- Transform vague requests into rich, detailed specifications
|
|
3849
|
+
- Less: "Create a visualization website"
|
|
3850
|
+
- More: "Create an enterprise-grade data visualization website with interactive charts, filtering capabilities, export functionality, and responsive design"
|
|
3851
|
+
|
|
3852
|
+
2. **Explain Intent ("Why")**
|
|
3853
|
+
- Add context about why this task matters
|
|
3854
|
+
- Example: "Your code will be reviewed for security vulnerabilities, so validate all inputs"
|
|
3855
|
+
- This helps the agent understand the purpose and provide more accurate results
|
|
3856
|
+
|
|
3857
|
+
3. **Provide Examples**
|
|
3858
|
+
- Show good patterns to follow and bad patterns to avoid
|
|
3859
|
+
- Example: "Good: Handle errors with specific messages like 'User not found'. Bad: Use generic try/catch with no message."
|
|
3860
|
+
|
|
3861
|
+
4. **Define Success Criteria**
|
|
3862
|
+
- What does "done" look like?
|
|
3863
|
+
- Example: "Complete when: tests pass, no linting errors, and manual verification in browser"
|
|
3864
|
+
|
|
3865
|
+
5. **Specify Constraints**
|
|
3866
|
+
- What to avoid, what not to do
|
|
3867
|
+
- Example: "Do not use external dependencies beyond the existing package.json"
|
|
3868
|
+
|
|
3869
|
+
For each sub-task, enhance the description following these principles. Call the decompose_tasks function with your analysis.`
|
|
3870
|
+
},
|
|
3871
|
+
{
|
|
3872
|
+
key: "pipeline.enhance.system",
|
|
3873
|
+
description: "Rewrites a coding request into a richer prompt (pipeline optimizer).",
|
|
3874
|
+
vars: [],
|
|
3875
|
+
body: `You are a prompt enhancement engine. Transform coding requests into rich, detailed prompts following these principles:
|
|
3876
|
+
|
|
3877
|
+
## Enhancement Principles (MiniMax Best Practices)
|
|
3878
|
+
|
|
3879
|
+
1. **Be Specific and Detailed**
|
|
3880
|
+
- Transform vague requests into rich specifications
|
|
3881
|
+
- Less: "Create a visualization website"
|
|
3882
|
+
- More: "Create an enterprise-grade data visualization website with interactive charts, filtering capabilities, export functionality, and responsive design"
|
|
3883
|
+
|
|
3884
|
+
2. **Explain Intent ("Why")**
|
|
3885
|
+
- Add context about why this task matters
|
|
3886
|
+
- Example: "Your code will be reviewed for security vulnerabilities, so validate all inputs"
|
|
3887
|
+
|
|
3888
|
+
3. **Provide Examples**
|
|
3889
|
+
- Show good patterns to follow and bad patterns to avoid
|
|
3890
|
+
- Example: "Good: Handle errors with specific messages. Bad: Use generic try/catch"
|
|
3891
|
+
|
|
3892
|
+
4. **Define Success Criteria**
|
|
3893
|
+
- What does "done" look like?
|
|
3894
|
+
- Example: "Complete when: tests pass, no linting errors"
|
|
3895
|
+
|
|
3896
|
+
5. **Specify Constraints**
|
|
3897
|
+
- What to avoid
|
|
3898
|
+
- Example: "Do not use external dependencies beyond existing packages"
|
|
3899
|
+
|
|
3900
|
+
Call the enhance_prompt function with your analysis.`
|
|
3901
|
+
},
|
|
3902
|
+
{
|
|
3903
|
+
key: "context.summary",
|
|
3904
|
+
description: "Short conversation summary stored for context reuse.",
|
|
3905
|
+
vars: [],
|
|
3906
|
+
body: `Summarize this conversation concisely in 2-4 sentences. Focus on:
|
|
3907
|
+
- What the user asked for
|
|
3908
|
+
- Key decisions made
|
|
3909
|
+
- Current state of the work
|
|
3910
|
+
- Any important context (file names, technologies, error messages)
|
|
3911
|
+
|
|
3912
|
+
Do NOT include greetings or meta-commentary. Just the facts.`
|
|
3913
|
+
},
|
|
3914
|
+
{
|
|
3915
|
+
key: "context.reasoning_summary",
|
|
3916
|
+
description: "Detailed summary of the earlier conversation for the reasoning tier.",
|
|
3917
|
+
vars: [],
|
|
3918
|
+
body: `Summarize the earlier part of this conversation for a senior AI assistant that will continue the work. Be detailed and preserve:
|
|
3919
|
+
- Specific file paths, function names, and code snippets mentioned
|
|
3920
|
+
- Decisions made and their rationale
|
|
3921
|
+
- Error messages, stack traces, or debugging steps taken
|
|
3922
|
+
- Current state of the task (what's done, what remains)
|
|
3923
|
+
- User preferences or constraints expressed
|
|
3924
|
+
|
|
3925
|
+
Write 3-8 sentences. Be concrete and technical, not vague.`
|
|
3926
|
+
},
|
|
3927
|
+
{
|
|
3928
|
+
key: "profile.adapter.system",
|
|
3929
|
+
description: "Classifies imported instruction sections as keep / on_demand / drop.",
|
|
3930
|
+
vars: [],
|
|
3931
|
+
body: `You prepare a user's personal instruction file (written for the Claude Code CLI) to be used by SpaceCode, a different coding agent that runs locally with these tools: read_file, write_file, edit_file, list_directory, search, bash, todo_write, memory_read, instructions_read. SpaceCode does NOT have: Claude Code hooks, ToolSearch/deferred tools, subagents (Task/Agent), skills or slash commands (/ship etc.), MCP tools (mcp__*), plan mode or worktrees.
|
|
3932
|
+
|
|
3933
|
+
For EACH section decide:
|
|
3934
|
+
- "keep": a short, general standing rule that applies to nearly every task (always loaded). Keep this set small: the total of all kept sections must stay under about 5000 characters.
|
|
3935
|
+
- "on_demand": useful only when working in a specific area (a tool, vendor, workflow). Give a one-line "summary" saying when to read it.
|
|
3936
|
+
- "drop": (the text is kept and stored on demand anyway; this only flags it) only meaningful inside Claude Code (describes its hooks, skills, subagents, ToolSearch, MCP tool names or its own settings) or is obsolete for SpaceCode. Give a short "reason".
|
|
3937
|
+
|
|
3938
|
+
You never rewrite or shorten text; you only classify. When unsure between drop and on_demand choose on_demand. When unsure between keep and on_demand choose on_demand.
|
|
3939
|
+
|
|
3940
|
+
Reply with ONLY a JSON array, one object per input section, in the same order: {"slug": string, "decision": "keep"|"on_demand"|"drop", "reason"?: string, "summary"?: string}. No prose, no code fences.`
|
|
3941
|
+
},
|
|
3942
|
+
{
|
|
3943
|
+
key: "route.code.system",
|
|
3944
|
+
description: 'System prompt of the "code" dynamic route (pipeline helper calls).',
|
|
3945
|
+
vars: [],
|
|
3946
|
+
body: `You are an expert software engineer. Write clean, correct, well-structured code with proper error handling.`
|
|
3947
|
+
},
|
|
3948
|
+
{
|
|
3949
|
+
key: "route.code-review.system",
|
|
3950
|
+
description: 'System prompt of the "code-review" dynamic route (pipeline helper calls).',
|
|
3951
|
+
vars: [],
|
|
3952
|
+
body: `You are a senior code reviewer. Analyze code for bugs, security issues, performance problems, and maintainability. Be specific and actionable.`
|
|
3953
|
+
},
|
|
3954
|
+
{
|
|
3955
|
+
key: "route.debugging.system",
|
|
3956
|
+
description: 'System prompt of the "debugging" dynamic route (pipeline helper calls).',
|
|
3957
|
+
vars: [],
|
|
3958
|
+
body: `You are an expert debugger. Diagnose issues methodically: identify symptoms, trace root causes, and provide concrete fixes. Explain your reasoning step by step.`
|
|
3959
|
+
},
|
|
3960
|
+
{
|
|
3961
|
+
key: "route.architecture.system",
|
|
3962
|
+
description: 'System prompt of the "architecture" dynamic route (pipeline helper calls).',
|
|
3963
|
+
vars: [],
|
|
3964
|
+
body: `You are a software architect. Focus on system design, scalability, trade-offs, and infrastructure decisions. Be concrete and practical.`
|
|
3965
|
+
},
|
|
3966
|
+
{
|
|
3967
|
+
key: "route.planning.system",
|
|
3968
|
+
description: 'System prompt of the "planning" dynamic route (pipeline helper calls).',
|
|
3969
|
+
vars: [],
|
|
3970
|
+
body: `You are a technical project manager. Create structured plans, roadmaps, and specifications. Use clear headings and actionable items.`
|
|
3971
|
+
},
|
|
3972
|
+
{
|
|
3973
|
+
key: "agent.summarizer.system",
|
|
3974
|
+
description: "Extracts decisions and work items from a session transcript (resume summary, /compact).",
|
|
3975
|
+
vars: [],
|
|
3976
|
+
body: `You are extracting structured information from a coding-agent conversation transcript. Identify (a) concrete DECISIONS made during the conversation (architectural choices, approach selections, explicit tradeoffs accepted) and (b) WORK ITEMS \u2014 discrete pieces of work mentioned as done, in-progress, or still needed, each classified as "open" or "done" based on the transcript. Respond with ONLY a JSON object matching exactly this shape, no prose before or after, no markdown code fences: {"decisions": [{"description": string}], "workItems": [{"description": string, "status": "open"|"done"}]}`
|
|
3977
|
+
},
|
|
3978
|
+
{
|
|
3979
|
+
key: "agent.summarizer.user_suffix",
|
|
3980
|
+
description: "Reminder appended after the transcript for the summarizer.",
|
|
3981
|
+
vars: [],
|
|
3982
|
+
body: `Respond with ONLY the JSON object described above \u2014 no prose, no markdown code fences.`
|
|
3983
|
+
}
|
|
3984
|
+
];
|
|
3848
3985
|
}
|
|
3849
|
-
|
|
3986
|
+
});
|
|
3987
|
+
|
|
3988
|
+
// ../shared/src/prompts/defaults-agent.ts
|
|
3989
|
+
var AGENT_PROMPT_LIST;
|
|
3990
|
+
var init_defaults_agent = __esm({
|
|
3991
|
+
"../shared/src/prompts/defaults-agent.ts"() {
|
|
3992
|
+
"use strict";
|
|
3993
|
+
AGENT_PROMPT_LIST = [
|
|
3994
|
+
{
|
|
3995
|
+
key: "agent.system.core",
|
|
3996
|
+
description: "Core system prompt of the SpaceCode agent (REPL and cloud).",
|
|
3997
|
+
vars: ["where", "tool_lines", "orient_line", "finish_line", "codegen_section", "commit_section", "working_dir", "project_card_section", "resume_section"],
|
|
3998
|
+
body: `You are SpaceCode Agent, a coding assistant running {{where}}.
|
|
3850
3999
|
|
|
3851
4000
|
## Tools
|
|
3852
|
-
|
|
4001
|
+
{{tool_lines}}
|
|
3853
4002
|
|
|
3854
4003
|
## Tool usage
|
|
3855
|
-
|
|
4004
|
+
{{orient_line}}
|
|
3856
4005
|
- Use search to find files by concept ("auth middleware", "billing webhook").
|
|
3857
4006
|
- Use bash for running commands, not for reading files. Use read_file instead.
|
|
3858
4007
|
- Prefer read_file + edit_file over write_file for existing files.
|
|
3859
|
-
|
|
4008
|
+
{{finish_line}}
|
|
3860
4009
|
|
|
3861
4010
|
## Editing
|
|
3862
4011
|
- Always read_file before edit_file \u2014 you need the current content.
|
|
3863
4012
|
- old_string must match exactly once. Include surrounding lines for uniqueness.
|
|
3864
4013
|
- Make small, targeted edits. Avoid rewriting entire files with write_file.
|
|
3865
|
-
|
|
3866
|
-
## Feature generation
|
|
3867
|
-
- For multi-file features (3+ new files), prefer build_feature over writing files manually.
|
|
3868
|
-
- build_feature leverages a component library \u2014 it reuses existing implementations when possible.
|
|
3869
|
-
- After build_feature, always run tests and review the generated code before committing.
|
|
3870
|
-
- For single-file changes, bug fixes, or config edits, use edit_file directly.
|
|
3871
|
-
` : ""}
|
|
4014
|
+
{{codegen_section}}
|
|
3872
4015
|
## Error recovery
|
|
3873
4016
|
- If edit_file fails (old_string not found), re-read the file \u2014 it may have changed \u2014 then retry with corrected old_string.
|
|
3874
4017
|
- If bash fails, read the error output and try a different approach. Never repeat the same failing command.
|
|
@@ -3879,24 +4022,125 @@ ${options.hasCodegenTools ? `
|
|
|
3879
4022
|
- For an audit or plan request, finish with the audit or plan itself (findings, then ordered next steps). Do not end by asking what to work on next.
|
|
3880
4023
|
- After changes, run relevant tests (bash: npm test, pytest, etc.) to verify.
|
|
3881
4024
|
- Commit logical units of work with descriptive messages.
|
|
3882
|
-
|
|
3883
|
-
|
|
4025
|
+
{{commit_section}}
|
|
4026
|
+
{{working_dir}}
|
|
4027
|
+
{{project_card_section}}{{resume_section}}
|
|
4028
|
+
Complete the user's task, then stop. Be concise in responses.`
|
|
4029
|
+
},
|
|
4030
|
+
{
|
|
4031
|
+
key: "agent.fragment.orient_card",
|
|
4032
|
+
description: "Tool-usage line when a project card is present.",
|
|
4033
|
+
vars: [],
|
|
4034
|
+
body: `- A project card below already holds the layout, commands, doc titles and excerpts, recent commits, branch and uncommitted changes. Do not re-list directories, re-run git status/log/diff, or re-read a doc just to see what the card shows; open a file only to go beyond its excerpt.`
|
|
4035
|
+
},
|
|
4036
|
+
{
|
|
4037
|
+
key: "agent.fragment.orient_default",
|
|
4038
|
+
description: "Tool-usage line when there is no project card.",
|
|
4039
|
+
vars: [],
|
|
4040
|
+
body: `- Use list_directory to orient yourself in the codebase before diving in.`
|
|
4041
|
+
},
|
|
4042
|
+
{
|
|
4043
|
+
key: "agent.fragment.finish_github",
|
|
4044
|
+
description: "Closing instruction when GitHub tools are available.",
|
|
4045
|
+
vars: [],
|
|
4046
|
+
body: `- After completing work, create a PR with create_pull_request. Commit and push changes first.`
|
|
4047
|
+
},
|
|
4048
|
+
{
|
|
4049
|
+
key: "agent.fragment.finish_commit",
|
|
4050
|
+
description: "Closing instruction without GitHub tools.",
|
|
4051
|
+
vars: [],
|
|
4052
|
+
body: `- After completing work, commit your changes with bash (git add + git commit).`
|
|
4053
|
+
},
|
|
4054
|
+
{
|
|
4055
|
+
key: "agent.fragment.codegen",
|
|
4056
|
+
description: "Feature-generation section (only when build_feature is registered).",
|
|
4057
|
+
vars: [],
|
|
4058
|
+
body: `## Feature generation
|
|
4059
|
+
- For multi-file features (3+ new files), prefer build_feature over writing files manually.
|
|
4060
|
+
- build_feature leverages a component library \u2014 it reuses existing implementations when possible.
|
|
4061
|
+
- After build_feature, always run tests and review the generated code before committing.
|
|
4062
|
+
- For single-file changes, bug fixes, or config edits, use edit_file directly.`
|
|
4063
|
+
},
|
|
4064
|
+
{
|
|
4065
|
+
key: "agent.fragment.commit",
|
|
4066
|
+
description: "Committing section (only when commit guidance is on).",
|
|
4067
|
+
vars: [],
|
|
4068
|
+
body: `## Committing
|
|
3884
4069
|
- After completing a logical unit of work, commit changes with a descriptive message using bash (git add + git commit).
|
|
3885
4070
|
- Use conventional commit format: feat:, fix:, refactor:, test:, docs:
|
|
3886
|
-
- Don't commit after every single file change \u2014 group related changes
|
|
3887
|
-
|
|
3888
|
-
|
|
3889
|
-
|
|
3890
|
-
|
|
3891
|
-
|
|
3892
|
-
|
|
3893
|
-
|
|
3894
|
-
|
|
3895
|
-
|
|
4071
|
+
- Don't commit after every single file change \u2014 group related changes.`
|
|
4072
|
+
},
|
|
4073
|
+
{
|
|
4074
|
+
key: "agent.fragment.resume",
|
|
4075
|
+
description: "Prior-turn summary injected on resume.",
|
|
4076
|
+
vars: ["summary"],
|
|
4077
|
+
body: `## Previously in this session
|
|
4078
|
+
{{summary}}`
|
|
4079
|
+
}
|
|
4080
|
+
];
|
|
4081
|
+
}
|
|
4082
|
+
});
|
|
4083
|
+
|
|
4084
|
+
// ../shared/src/prompts/index.ts
|
|
4085
|
+
function renderPrompt(body, vars = {}) {
|
|
4086
|
+
return body.replace(VAR, (_m, name) => {
|
|
4087
|
+
if (!(name in vars)) throw new Error(`prompt variable {{${name}}} was not provided`);
|
|
4088
|
+
return vars[name];
|
|
4089
|
+
});
|
|
4090
|
+
}
|
|
4091
|
+
var DEFAULT_PROMPTS, VAR;
|
|
4092
|
+
var init_prompts = __esm({
|
|
4093
|
+
"../shared/src/prompts/index.ts"() {
|
|
4094
|
+
init_defaults_core();
|
|
4095
|
+
init_defaults_agent();
|
|
4096
|
+
DEFAULT_PROMPTS = Object.freeze(
|
|
4097
|
+
Object.fromEntries([...DEFAULT_PROMPT_LIST, ...AGENT_PROMPT_LIST].map((p) => [p.key, p]))
|
|
4098
|
+
);
|
|
4099
|
+
VAR = /\{\{\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*\}\}/g;
|
|
4100
|
+
}
|
|
4101
|
+
});
|
|
4102
|
+
|
|
4103
|
+
// ../agent/src/prompt.ts
|
|
4104
|
+
function buildSystemPrompt(options) {
|
|
4105
|
+
const workingDir = options.localCwd ? `Working directory: ${options.localCwd}` : options.repoName ? `Working directory: /home/user/${options.repoName}` : "Working directory: empty workspace";
|
|
4106
|
+
const where = options.localCwd ? "on the user's machine" : "in the cloud";
|
|
4107
|
+
const toolLines = [
|
|
4108
|
+
"- read_file / write_file / edit_file / list_directory \u2014 instant file operations",
|
|
4109
|
+
"- search \u2014 semantic code search by concept or keyword",
|
|
4110
|
+
"- bash \u2014 shell commands (tests, builds, git, installs)"
|
|
4111
|
+
];
|
|
4112
|
+
if (options.hasPreviewTool) {
|
|
4113
|
+
toolLines.push("- preview \u2014 start or check a live preview of the app (front-end projects only)");
|
|
4114
|
+
}
|
|
4115
|
+
if (options.hasGitHubTools) {
|
|
4116
|
+
toolLines.push("- create_pull_request \u2014 create a GitHub PR from the current branch");
|
|
4117
|
+
}
|
|
4118
|
+
if (options.hasSentryTools) {
|
|
4119
|
+
toolLines.push("- sentry_list_issues / sentry_get_issue \u2014 view production errors (when connected)");
|
|
4120
|
+
}
|
|
4121
|
+
if (options.hasCodegenTools) {
|
|
4122
|
+
toolLines.push("- build_feature \u2014 generate a complete feature with tests using the platform codegen service. Use for multi-file features or new modules. Files are written to workspace; run tests afterwards.");
|
|
4123
|
+
}
|
|
4124
|
+
const t = (key) => options.templates?.[key] ?? DEFAULT_PROMPTS[key].body;
|
|
4125
|
+
const wrap = (body) => `
|
|
4126
|
+
${body}
|
|
4127
|
+
`;
|
|
4128
|
+
return renderPrompt(t("agent.system.core"), {
|
|
4129
|
+
where,
|
|
4130
|
+
tool_lines: toolLines.join("\n"),
|
|
4131
|
+
orient_line: options.projectCard ? t("agent.fragment.orient_card") : t("agent.fragment.orient_default"),
|
|
4132
|
+
finish_line: options.hasGitHubTools ? t("agent.fragment.finish_github") : t("agent.fragment.finish_commit"),
|
|
4133
|
+
codegen_section: options.hasCodegenTools ? wrap(t("agent.fragment.codegen")) : "",
|
|
4134
|
+
commit_section: options.commitGuidance ? wrap(t("agent.fragment.commit")) : "",
|
|
4135
|
+
working_dir: workingDir,
|
|
4136
|
+
project_card_section: options.projectCard ? wrap(options.projectCard) : "",
|
|
4137
|
+
resume_section: options.resumeSummary ? wrap(renderPrompt(t("agent.fragment.resume"), { summary: options.resumeSummary })) : ""
|
|
4138
|
+
});
|
|
3896
4139
|
}
|
|
3897
4140
|
var init_prompt = __esm({
|
|
3898
4141
|
"../agent/src/prompt.ts"() {
|
|
3899
4142
|
"use strict";
|
|
4143
|
+
init_prompts();
|
|
3900
4144
|
}
|
|
3901
4145
|
});
|
|
3902
4146
|
|
|
@@ -4096,9 +4340,9 @@ function createFileTools(store) {
|
|
|
4096
4340
|
const handlers = {
|
|
4097
4341
|
read_file: async (input) => {
|
|
4098
4342
|
const path12 = input.path;
|
|
4099
|
-
const
|
|
4100
|
-
if (
|
|
4101
|
-
return { output:
|
|
4343
|
+
const cached3 = readCache.get(path12);
|
|
4344
|
+
if (cached3 !== void 0) {
|
|
4345
|
+
return { output: cached3 };
|
|
4102
4346
|
}
|
|
4103
4347
|
const content = await store.readFile(path12);
|
|
4104
4348
|
if (content === null) {
|
|
@@ -4158,12 +4402,12 @@ Include more surrounding context to make old_string unique.`,
|
|
|
4158
4402
|
},
|
|
4159
4403
|
list_directory: async (input) => {
|
|
4160
4404
|
const path12 = input.path;
|
|
4161
|
-
const
|
|
4162
|
-
if (
|
|
4163
|
-
if (
|
|
4405
|
+
const cached3 = listCache.get(path12);
|
|
4406
|
+
if (cached3 !== void 0) {
|
|
4407
|
+
if (cached3.length === 0) {
|
|
4164
4408
|
return { output: `Empty or not found: ${path12}` };
|
|
4165
4409
|
}
|
|
4166
|
-
return { output:
|
|
4410
|
+
return { output: cached3.join("\n") };
|
|
4167
4411
|
}
|
|
4168
4412
|
const entries = await store.listDirectory(path12);
|
|
4169
4413
|
listCache.set(path12, entries);
|
|
@@ -5877,10 +6121,10 @@ async function summarizeConversation(messages, config) {
|
|
|
5877
6121
|
return { decisions: [], workItems: [], summaryText: "", inputTokens: 0, outputTokens: 0 };
|
|
5878
6122
|
}
|
|
5879
6123
|
const transcript = buildTranscriptForSummarization(messages, MAX_TRANSCRIPT_CHARS);
|
|
5880
|
-
const systemPrompt =
|
|
6124
|
+
const systemPrompt = config.templates?.["agent.summarizer.system"] ?? DEFAULT_PROMPTS["agent.summarizer.system"].body;
|
|
5881
6125
|
const userContent = `${transcript}
|
|
5882
6126
|
|
|
5883
|
-
|
|
6127
|
+
${config.templates?.["agent.summarizer.user_suffix"] ?? DEFAULT_PROMPTS["agent.summarizer.user_suffix"].body}`;
|
|
5884
6128
|
const response = await fetch(`${config.apiUrl}/v1/messages`, {
|
|
5885
6129
|
method: "POST",
|
|
5886
6130
|
headers: {
|
|
@@ -5974,6 +6218,7 @@ var DEFAULT_SUMMARIZER_MODEL, MAX_TRANSCRIPT_CHARS, MAX_TOKENS2;
|
|
|
5974
6218
|
var init_summarizer = __esm({
|
|
5975
6219
|
"../agent/src/summarizer.ts"() {
|
|
5976
6220
|
"use strict";
|
|
6221
|
+
init_prompts();
|
|
5977
6222
|
DEFAULT_SUMMARIZER_MODEL = "claude-haiku-4-5";
|
|
5978
6223
|
MAX_TRANSCRIPT_CHARS = 4e4;
|
|
5979
6224
|
MAX_TOKENS2 = 4096;
|
|
@@ -6650,17 +6895,17 @@ var init_memory_tool = __esm({
|
|
|
6650
6895
|
// ../agent/src/import/profile-loader.ts
|
|
6651
6896
|
async function loadProfile(opts) {
|
|
6652
6897
|
const { client, cache: cache4, projectKeys } = opts;
|
|
6653
|
-
let
|
|
6898
|
+
let cached3 = null;
|
|
6654
6899
|
let cacheError;
|
|
6655
6900
|
try {
|
|
6656
|
-
|
|
6901
|
+
cached3 = await cache4.read();
|
|
6657
6902
|
} catch (err) {
|
|
6658
6903
|
cacheError = `profile cache unreadable: ${err instanceof Error ? err.message : String(err)}`;
|
|
6659
6904
|
}
|
|
6660
|
-
const sameProject =
|
|
6905
|
+
const sameProject = cached3 !== null && cached3.projectKey !== null && projectKeys.includes(cached3.projectKey);
|
|
6661
6906
|
try {
|
|
6662
|
-
const index = await client.index(sameProject ?
|
|
6663
|
-
if (index === null && sameProject) return { profile:
|
|
6907
|
+
const index = await client.index(sameProject ? cached3.version : void 0);
|
|
6908
|
+
if (index === null && sameProject) return { profile: cached3, source: "live" };
|
|
6664
6909
|
if (index === null) throw new Error("profile API answered 304 with no usable cached copy");
|
|
6665
6910
|
const has2 = (kind, name) => index.assets.some((a) => a.kind === kind && a.name === name);
|
|
6666
6911
|
const chosen = projectKeys.find((k2) => has2("memory", `${k2}.index`)) ?? null;
|
|
@@ -6682,8 +6927,8 @@ async function loadProfile(opts) {
|
|
|
6682
6927
|
return { profile, source: "live", ...cacheError ? { error: cacheError } : {} };
|
|
6683
6928
|
} catch (err) {
|
|
6684
6929
|
const error = `${err instanceof Error ? err.message : String(err)}${cacheError ? `; ${cacheError}` : ""}`;
|
|
6685
|
-
if (!
|
|
6686
|
-
return { profile: sameProject ?
|
|
6930
|
+
if (!cached3) return { profile: null, source: "none", error };
|
|
6931
|
+
return { profile: sameProject ? cached3 : { ...cached3, memoryIndex: null, projectKey: null }, source: "cache", error };
|
|
6687
6932
|
}
|
|
6688
6933
|
}
|
|
6689
6934
|
var init_profile_loader = __esm({
|
|
@@ -9386,7 +9631,7 @@ var require_signal_exit = __commonJS({
|
|
|
9386
9631
|
}
|
|
9387
9632
|
assert.equal(typeof cb, "function", "a callback must be provided for exit handler");
|
|
9388
9633
|
if (loaded === false) {
|
|
9389
|
-
|
|
9634
|
+
load2();
|
|
9390
9635
|
}
|
|
9391
9636
|
var ev = "exit";
|
|
9392
9637
|
if (opts && opts.alwaysLast) {
|
|
@@ -9446,7 +9691,7 @@ var require_signal_exit = __commonJS({
|
|
|
9446
9691
|
return signals;
|
|
9447
9692
|
};
|
|
9448
9693
|
loaded = false;
|
|
9449
|
-
|
|
9694
|
+
load2 = function load3() {
|
|
9450
9695
|
if (loaded || !processOk(global.process)) {
|
|
9451
9696
|
return;
|
|
9452
9697
|
}
|
|
@@ -9463,7 +9708,7 @@ var require_signal_exit = __commonJS({
|
|
|
9463
9708
|
process13.emit = processEmit;
|
|
9464
9709
|
process13.reallyExit = processReallyExit;
|
|
9465
9710
|
};
|
|
9466
|
-
module.exports.load =
|
|
9711
|
+
module.exports.load = load2;
|
|
9467
9712
|
originalProcessReallyExit = process13.reallyExit;
|
|
9468
9713
|
processReallyExit = function processReallyExit2(code) {
|
|
9469
9714
|
if (!processOk(global.process)) {
|
|
@@ -9499,7 +9744,7 @@ var require_signal_exit = __commonJS({
|
|
|
9499
9744
|
var emit;
|
|
9500
9745
|
var sigListeners;
|
|
9501
9746
|
var loaded;
|
|
9502
|
-
var
|
|
9747
|
+
var load2;
|
|
9503
9748
|
var originalProcessReallyExit;
|
|
9504
9749
|
var processReallyExit;
|
|
9505
9750
|
var originalProcessEmit;
|
|
@@ -44082,7 +44327,7 @@ var require_core = __commonJS({
|
|
|
44082
44327
|
return match && match.index === 0;
|
|
44083
44328
|
}
|
|
44084
44329
|
var BACKREF_RE = /\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./;
|
|
44085
|
-
function
|
|
44330
|
+
function join14(regexps, separator = "|") {
|
|
44086
44331
|
let numCaptures = 0;
|
|
44087
44332
|
return regexps.map((regex2) => {
|
|
44088
44333
|
numCaptures += 1;
|
|
@@ -44386,7 +44631,7 @@ var require_core = __commonJS({
|
|
|
44386
44631
|
this.exec = () => null;
|
|
44387
44632
|
}
|
|
44388
44633
|
const terminators = this.regexes.map((el) => el[1]);
|
|
44389
|
-
this.matcherRe = langRe(
|
|
44634
|
+
this.matcherRe = langRe(join14(terminators), true);
|
|
44390
44635
|
this.lastIndex = 0;
|
|
44391
44636
|
}
|
|
44392
44637
|
/** @param {string} s */
|
|
@@ -48163,7 +48408,7 @@ var require_bash = __commonJS({
|
|
|
48163
48408
|
return joined;
|
|
48164
48409
|
}
|
|
48165
48410
|
function bash(hljs) {
|
|
48166
|
-
const
|
|
48411
|
+
const VAR2 = {};
|
|
48167
48412
|
const BRACED_VAR = {
|
|
48168
48413
|
begin: /\$\{/,
|
|
48169
48414
|
end: /\}/,
|
|
@@ -48171,12 +48416,12 @@ var require_bash = __commonJS({
|
|
|
48171
48416
|
"self",
|
|
48172
48417
|
{
|
|
48173
48418
|
begin: /:-/,
|
|
48174
|
-
contains: [
|
|
48419
|
+
contains: [VAR2]
|
|
48175
48420
|
}
|
|
48176
48421
|
// default values
|
|
48177
48422
|
]
|
|
48178
48423
|
};
|
|
48179
|
-
Object.assign(
|
|
48424
|
+
Object.assign(VAR2, {
|
|
48180
48425
|
className: "variable",
|
|
48181
48426
|
variants: [
|
|
48182
48427
|
{ begin: concat(
|
|
@@ -48212,7 +48457,7 @@ var require_bash = __commonJS({
|
|
|
48212
48457
|
end: /"/,
|
|
48213
48458
|
contains: [
|
|
48214
48459
|
hljs.BACKSLASH_ESCAPE,
|
|
48215
|
-
|
|
48460
|
+
VAR2,
|
|
48216
48461
|
SUBST
|
|
48217
48462
|
]
|
|
48218
48463
|
};
|
|
@@ -48232,7 +48477,7 @@ var require_bash = __commonJS({
|
|
|
48232
48477
|
contains: [
|
|
48233
48478
|
{ begin: /\d+#[0-9a-f]+/, className: "number" },
|
|
48234
48479
|
hljs.NUMBER_MODE,
|
|
48235
|
-
|
|
48480
|
+
VAR2
|
|
48236
48481
|
]
|
|
48237
48482
|
};
|
|
48238
48483
|
const SH_LIKE_SHELLS = [
|
|
@@ -48282,7 +48527,7 @@ var require_bash = __commonJS({
|
|
|
48282
48527
|
QUOTE_STRING,
|
|
48283
48528
|
ESCAPED_QUOTE,
|
|
48284
48529
|
APOS_STRING,
|
|
48285
|
-
|
|
48530
|
+
VAR2
|
|
48286
48531
|
]
|
|
48287
48532
|
};
|
|
48288
48533
|
}
|
|
@@ -67905,7 +68150,7 @@ var require_perl = __commonJS({
|
|
|
67905
68150
|
end: /\}/
|
|
67906
68151
|
// contains defined later
|
|
67907
68152
|
};
|
|
67908
|
-
const
|
|
68153
|
+
const VAR2 = {
|
|
67909
68154
|
variants: [
|
|
67910
68155
|
{
|
|
67911
68156
|
begin: /\$\d/
|
|
@@ -67927,7 +68172,7 @@ var require_perl = __commonJS({
|
|
|
67927
68172
|
const STRING_CONTAINS = [
|
|
67928
68173
|
hljs.BACKSLASH_ESCAPE,
|
|
67929
68174
|
SUBST,
|
|
67930
|
-
|
|
68175
|
+
VAR2
|
|
67931
68176
|
];
|
|
67932
68177
|
const REGEX_DELIMS = [
|
|
67933
68178
|
/!/,
|
|
@@ -67962,7 +68207,7 @@ var require_perl = __commonJS({
|
|
|
67962
68207
|
);
|
|
67963
68208
|
};
|
|
67964
68209
|
const PERL_DEFAULT_CONTAINS = [
|
|
67965
|
-
|
|
68210
|
+
VAR2,
|
|
67966
68211
|
hljs.HASH_COMMENT_MODE,
|
|
67967
68212
|
hljs.COMMENT(
|
|
67968
68213
|
/^=\w/,
|
|
@@ -68429,7 +68674,7 @@ var require_n1ql = __commonJS({
|
|
|
68429
68674
|
var require_nginx = __commonJS({
|
|
68430
68675
|
"../../node_modules/highlight.js/lib/languages/nginx.js"(exports, module) {
|
|
68431
68676
|
function nginx(hljs) {
|
|
68432
|
-
const
|
|
68677
|
+
const VAR2 = {
|
|
68433
68678
|
className: "variable",
|
|
68434
68679
|
variants: [
|
|
68435
68680
|
{
|
|
@@ -68458,7 +68703,7 @@ var require_nginx = __commonJS({
|
|
|
68458
68703
|
className: "string",
|
|
68459
68704
|
contains: [
|
|
68460
68705
|
hljs.BACKSLASH_ESCAPE,
|
|
68461
|
-
|
|
68706
|
+
VAR2
|
|
68462
68707
|
],
|
|
68463
68708
|
variants: [
|
|
68464
68709
|
{
|
|
@@ -68477,13 +68722,13 @@ var require_nginx = __commonJS({
|
|
|
68477
68722
|
end: "\\s",
|
|
68478
68723
|
endsWithParent: true,
|
|
68479
68724
|
excludeEnd: true,
|
|
68480
|
-
contains: [
|
|
68725
|
+
contains: [VAR2]
|
|
68481
68726
|
},
|
|
68482
68727
|
{
|
|
68483
68728
|
className: "regexp",
|
|
68484
68729
|
contains: [
|
|
68485
68730
|
hljs.BACKSLASH_ESCAPE,
|
|
68486
|
-
|
|
68731
|
+
VAR2
|
|
68487
68732
|
],
|
|
68488
68733
|
variants: [
|
|
68489
68734
|
{
|
|
@@ -68518,7 +68763,7 @@ var require_nginx = __commonJS({
|
|
|
68518
68763
|
begin: "\\b\\d+[kKmMgGdshdwy]*\\b",
|
|
68519
68764
|
relevance: 0
|
|
68520
68765
|
},
|
|
68521
|
-
|
|
68766
|
+
VAR2
|
|
68522
68767
|
]
|
|
68523
68768
|
};
|
|
68524
68769
|
return {
|
|
@@ -69984,7 +70229,7 @@ var require_powershell = __commonJS({
|
|
|
69984
70229
|
begin: "`[\\s\\S]",
|
|
69985
70230
|
relevance: 0
|
|
69986
70231
|
};
|
|
69987
|
-
const
|
|
70232
|
+
const VAR2 = {
|
|
69988
70233
|
className: "variable",
|
|
69989
70234
|
variants: [
|
|
69990
70235
|
{
|
|
@@ -70017,7 +70262,7 @@ var require_powershell = __commonJS({
|
|
|
70017
70262
|
],
|
|
70018
70263
|
contains: [
|
|
70019
70264
|
BACKTICK_ESCAPE,
|
|
70020
|
-
|
|
70265
|
+
VAR2,
|
|
70021
70266
|
{
|
|
70022
70267
|
className: "variable",
|
|
70023
70268
|
begin: /\$[A-z]/,
|
|
@@ -70108,7 +70353,7 @@ var require_powershell = __commonJS({
|
|
|
70108
70353
|
end: /\)/,
|
|
70109
70354
|
className: "params",
|
|
70110
70355
|
relevance: 0,
|
|
70111
|
-
contains: [
|
|
70356
|
+
contains: [VAR2]
|
|
70112
70357
|
}
|
|
70113
70358
|
// CMDLETS
|
|
70114
70359
|
]
|
|
@@ -70179,7 +70424,7 @@ var require_powershell = __commonJS({
|
|
|
70179
70424
|
APOS_STRING,
|
|
70180
70425
|
// PS_NEW_OBJECT_TYPE,
|
|
70181
70426
|
CMDLETS,
|
|
70182
|
-
|
|
70427
|
+
VAR2,
|
|
70183
70428
|
LITERAL,
|
|
70184
70429
|
HASH_SIGNS
|
|
70185
70430
|
];
|
|
@@ -70301,7 +70546,7 @@ var require_prolog = __commonJS({
|
|
|
70301
70546
|
begin: /[a-z][A-Za-z0-9_]*/,
|
|
70302
70547
|
relevance: 0
|
|
70303
70548
|
};
|
|
70304
|
-
const
|
|
70549
|
+
const VAR2 = {
|
|
70305
70550
|
className: "symbol",
|
|
70306
70551
|
variants: [
|
|
70307
70552
|
{
|
|
@@ -70350,7 +70595,7 @@ var require_prolog = __commonJS({
|
|
|
70350
70595
|
};
|
|
70351
70596
|
const inner = [
|
|
70352
70597
|
ATOM,
|
|
70353
|
-
|
|
70598
|
+
VAR2,
|
|
70354
70599
|
PARENTED,
|
|
70355
70600
|
PRED_OP,
|
|
70356
70601
|
LIST,
|
|
@@ -71895,7 +72140,7 @@ var require_routeros = __commonJS({
|
|
|
71895
72140
|
const COMMON_COMMANDS = "add remove enable disable set get print export edit find run debug error info warning";
|
|
71896
72141
|
const LITERALS = "true false yes no nothing nil null";
|
|
71897
72142
|
const OBJECTS = "traffic-flow traffic-generator firewall scheduler aaa accounting address-list address align area bandwidth-server bfd bgp bridge client clock community config connection console customer default dhcp-client dhcp-server discovery dns e-mail ethernet filter firmware gps graphing group hardware health hotspot identity igmp-proxy incoming instance interface ip ipsec ipv6 irq l2tp-server lcd ldp logging mac-server mac-winbox mangle manual mirror mme mpls nat nd neighbor network note ntp ospf ospf-v3 ovpn-server page peer pim ping policy pool port ppp pppoe-client pptp-server prefix profile proposal proxy queue radius resource rip ripng route routing screen script security-profiles server service service-port settings shares smb sms sniffer snmp snooper socks sstp-server system tool tracking type upgrade upnp user-manager users user vlan secret vrrp watchdog web-access wireless pptp pppoe lan wan layer7-protocol lease simple raw";
|
|
71898
|
-
const
|
|
72143
|
+
const VAR2 = {
|
|
71899
72144
|
className: "variable",
|
|
71900
72145
|
variants: [
|
|
71901
72146
|
{
|
|
@@ -71912,7 +72157,7 @@ var require_routeros = __commonJS({
|
|
|
71912
72157
|
end: /"/,
|
|
71913
72158
|
contains: [
|
|
71914
72159
|
hljs.BACKSLASH_ESCAPE,
|
|
71915
|
-
|
|
72160
|
+
VAR2,
|
|
71916
72161
|
{
|
|
71917
72162
|
className: "variable",
|
|
71918
72163
|
begin: /\$\(/,
|
|
@@ -71962,7 +72207,7 @@ var require_routeros = __commonJS({
|
|
|
71962
72207
|
hljs.COMMENT("^#", "$"),
|
|
71963
72208
|
QUOTE_STRING,
|
|
71964
72209
|
APOS_STRING,
|
|
71965
|
-
|
|
72210
|
+
VAR2,
|
|
71966
72211
|
// attribute=value
|
|
71967
72212
|
{
|
|
71968
72213
|
// > is to avoid matches with => in other grammars
|
|
@@ -71981,7 +72226,7 @@ var require_routeros = __commonJS({
|
|
|
71981
72226
|
contains: [
|
|
71982
72227
|
QUOTE_STRING,
|
|
71983
72228
|
APOS_STRING,
|
|
71984
|
-
|
|
72229
|
+
VAR2,
|
|
71985
72230
|
{
|
|
71986
72231
|
className: "literal",
|
|
71987
72232
|
begin: "\\b(" + LITERALS.split(" ").join("|") + ")\\b"
|
|
@@ -78263,7 +78508,7 @@ var require_xquery = __commonJS({
|
|
|
78263
78508
|
begin: /\bxquery version "[13]\.[01]"\s?(?:encoding ".+")?/,
|
|
78264
78509
|
end: /;/
|
|
78265
78510
|
};
|
|
78266
|
-
const
|
|
78511
|
+
const VAR2 = {
|
|
78267
78512
|
className: "variable",
|
|
78268
78513
|
begin: /[$][\w\-:]+/
|
|
78269
78514
|
};
|
|
@@ -78332,7 +78577,7 @@ var require_xquery = __commonJS({
|
|
|
78332
78577
|
]
|
|
78333
78578
|
};
|
|
78334
78579
|
const CONTAINS = [
|
|
78335
|
-
|
|
78580
|
+
VAR2,
|
|
78336
78581
|
BUILT_IN,
|
|
78337
78582
|
STRING,
|
|
78338
78583
|
NUMBER,
|
|
@@ -103855,6 +104100,65 @@ var init_project_card_runtime = __esm({
|
|
|
103855
104100
|
}
|
|
103856
104101
|
});
|
|
103857
104102
|
|
|
104103
|
+
// src/prompt-runtime.ts
|
|
104104
|
+
import { join as join8 } from "node:path";
|
|
104105
|
+
async function load(deps) {
|
|
104106
|
+
if (deps.env.SPACECODE_PROMPTS === "off") return { templates: {}, statusLine: "prompts: built-in defaults (SPACECODE_PROMPTS=off)" };
|
|
104107
|
+
const dir = deps.env.SPACECODE_CONFIG_DIR?.trim() || join8(deps.homedir(), ".spacecode");
|
|
104108
|
+
const file = join8(dir, "prompts-cache.json");
|
|
104109
|
+
const fromDisk = async (why) => {
|
|
104110
|
+
try {
|
|
104111
|
+
const raw = JSON.parse(await deps.readFile(file));
|
|
104112
|
+
const templates = raw.templates ?? {};
|
|
104113
|
+
return { templates, statusLine: `prompts: ${Object.keys(templates).length} tuned (STALE: served from cache; ${why})` };
|
|
104114
|
+
} catch {
|
|
104115
|
+
return { templates: {}, statusLine: `prompts: built-in defaults (${why})` };
|
|
104116
|
+
}
|
|
104117
|
+
};
|
|
104118
|
+
let apiKey;
|
|
104119
|
+
try {
|
|
104120
|
+
apiKey = await resolveApiKey({ env: deps.env, readFile: deps.readFile, homedir: deps.homedir });
|
|
104121
|
+
} catch (err) {
|
|
104122
|
+
return fromDisk(err instanceof Error ? err.message : String(err));
|
|
104123
|
+
}
|
|
104124
|
+
if (!apiKey) return fromDisk("not signed in");
|
|
104125
|
+
try {
|
|
104126
|
+
const res = await deps.fetch(`${backendUrl(deps.env)}/api/prompts`, {
|
|
104127
|
+
headers: { Authorization: `Bearer ${apiKey}`, "x-api-key": apiKey },
|
|
104128
|
+
signal: AbortSignal.timeout(3e3)
|
|
104129
|
+
});
|
|
104130
|
+
if (!res.ok) return fromDisk(`prompt API returned ${res.status}`);
|
|
104131
|
+
const { prompts } = await res.json();
|
|
104132
|
+
const templates = Object.fromEntries(prompts.filter((p) => p.source === "db").map((p) => [p.key, p.body]));
|
|
104133
|
+
try {
|
|
104134
|
+
await deps.mkdir(dir);
|
|
104135
|
+
await deps.writeFile(file, JSON.stringify({ fetchedAt: new Date((deps.now ?? Date.now)()).toISOString(), templates }));
|
|
104136
|
+
} catch (err) {
|
|
104137
|
+
console.error("[prompts] could not write the prompt cache", err instanceof Error ? err.message : String(err));
|
|
104138
|
+
}
|
|
104139
|
+
const n = Object.keys(templates).length;
|
|
104140
|
+
return { templates, statusLine: n ? `prompts: ${n} tuned override(s): ${Object.keys(templates).join(", ")}` : "prompts: built-in defaults (none tuned)" };
|
|
104141
|
+
} catch (err) {
|
|
104142
|
+
return fromDisk(`fetch failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
104143
|
+
}
|
|
104144
|
+
}
|
|
104145
|
+
function loadPromptTemplates(deps) {
|
|
104146
|
+
const now = (deps.now ?? Date.now)();
|
|
104147
|
+
if (cached2 && now - cached2.at < TTL_MS2) return cached2.pending;
|
|
104148
|
+
const pending = load(deps);
|
|
104149
|
+
cached2 = { at: now, pending };
|
|
104150
|
+
return pending;
|
|
104151
|
+
}
|
|
104152
|
+
var TTL_MS2, cached2;
|
|
104153
|
+
var init_prompt_runtime = __esm({
|
|
104154
|
+
"src/prompt-runtime.ts"() {
|
|
104155
|
+
"use strict";
|
|
104156
|
+
init_api_key();
|
|
104157
|
+
init_profile_runtime();
|
|
104158
|
+
TTL_MS2 = 10 * 6e4;
|
|
104159
|
+
}
|
|
104160
|
+
});
|
|
104161
|
+
|
|
103858
104162
|
// src/shell-turn.ts
|
|
103859
104163
|
function shellCommandOf(prompt) {
|
|
103860
104164
|
return prompt.startsWith("!") ? prompt.slice(1).trim() : null;
|
|
@@ -104279,7 +104583,7 @@ var init_recording_chunks = __esm({
|
|
|
104279
104583
|
// src/recording/recorder.ts
|
|
104280
104584
|
import { createHash as createHash4 } from "node:crypto";
|
|
104281
104585
|
import { mkdir as mkdir4, readFile as readFile6, rename as rename4, rm as rm2, writeFile as writeFile4, readdir as readdir5, stat as stat3 } from "node:fs/promises";
|
|
104282
|
-
import { join as
|
|
104586
|
+
import { join as join9 } from "node:path";
|
|
104283
104587
|
function projectHash(root) {
|
|
104284
104588
|
return createHash4("sha256").update(root).digest("hex");
|
|
104285
104589
|
}
|
|
@@ -104290,24 +104594,24 @@ function createRecorder(deps) {
|
|
|
104290
104594
|
let inflight = null;
|
|
104291
104595
|
let retryAttempt = 0;
|
|
104292
104596
|
let timerArmed = false;
|
|
104293
|
-
const stateFile = (sessionId) =>
|
|
104597
|
+
const stateFile = (sessionId) => join9(deps.dir, `${sessionId}.json`);
|
|
104294
104598
|
async function save(sessionId, st) {
|
|
104295
104599
|
await mkdir4(deps.dir, { recursive: true, mode: 448 });
|
|
104296
104600
|
const tmp = `${stateFile(sessionId)}.${deps.randomId()}.tmp`;
|
|
104297
104601
|
await writeFile4(tmp, JSON.stringify(st), { mode: 384 });
|
|
104298
104602
|
await rename4(tmp, stateFile(sessionId));
|
|
104299
104603
|
}
|
|
104300
|
-
async function
|
|
104301
|
-
const
|
|
104302
|
-
if (
|
|
104604
|
+
async function load2(sessionId) {
|
|
104605
|
+
const cached3 = states.get(sessionId);
|
|
104606
|
+
if (cached3) return cached3;
|
|
104303
104607
|
let st;
|
|
104304
104608
|
try {
|
|
104305
104609
|
st = JSON.parse(await readFile6(stateFile(sessionId), "utf8"));
|
|
104306
104610
|
} catch (e) {
|
|
104307
104611
|
if (e.code !== "ENOENT") {
|
|
104308
|
-
const bad =
|
|
104612
|
+
const bad = join9(deps.dir, "bad");
|
|
104309
104613
|
await mkdir4(bad, { recursive: true, mode: 448 });
|
|
104310
|
-
await rename4(stateFile(sessionId),
|
|
104614
|
+
await rename4(stateFile(sessionId), join9(bad, `${sessionId}.${deps.now()}.json`)).catch((err) => deps.log(`recording: could not quarantine ${sessionId}: ${String(err)}`));
|
|
104311
104615
|
lastError = `recording state for ${sessionId} was unreadable and was quarantined`;
|
|
104312
104616
|
deps.log(`recording: ${lastError}`);
|
|
104313
104617
|
}
|
|
@@ -104324,7 +104628,7 @@ function createRecorder(deps) {
|
|
|
104324
104628
|
async function record(sessionId, messages, meta) {
|
|
104325
104629
|
try {
|
|
104326
104630
|
if (off2) return;
|
|
104327
|
-
const st = await
|
|
104631
|
+
const st = await load2(sessionId);
|
|
104328
104632
|
if (st.stopped) return;
|
|
104329
104633
|
if (st.hashes.length === 0 && st.nextSeq === 1 && meta.parentRecordingId) st.parentRecordingId = meta.parentRecordingId;
|
|
104330
104634
|
st.meta = meta;
|
|
@@ -104477,7 +104781,7 @@ function createRecorder(deps) {
|
|
|
104477
104781
|
for (const n of names) {
|
|
104478
104782
|
if (!n.endsWith(".json")) continue;
|
|
104479
104783
|
const id = n.slice(0, -5);
|
|
104480
|
-
const st = await
|
|
104784
|
+
const st = await load2(id);
|
|
104481
104785
|
if (st.queue.length === 0) states.delete(id);
|
|
104482
104786
|
}
|
|
104483
104787
|
if ([...states.values()].some((s) => s.queue.length > 0)) void flush();
|
|
@@ -104498,7 +104802,7 @@ var init_recorder = __esm({
|
|
|
104498
104802
|
|
|
104499
104803
|
// src/recording/recording-runtime.ts
|
|
104500
104804
|
import { mkdir as mkdir5, readFile as readFile7, writeFile as writeFile5, stat as stat4 } from "node:fs/promises";
|
|
104501
|
-
import { join as
|
|
104805
|
+
import { join as join10, sep as sep2 } from "node:path";
|
|
104502
104806
|
function matchesExclude(pattern, root) {
|
|
104503
104807
|
const re3 = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, "\0").replace(/\*/g, `[^${sep2 === "\\" ? "\\\\" : "/"}]*`).replace(/\u0000/g, ".*");
|
|
104504
104808
|
return new RegExp(`^${re3}(?:[/\\\\].*)?$`).test(root);
|
|
@@ -104513,8 +104817,8 @@ async function exists(path12) {
|
|
|
104513
104817
|
}
|
|
104514
104818
|
}
|
|
104515
104819
|
function createRecordingRuntime(deps) {
|
|
104516
|
-
const dir =
|
|
104517
|
-
const noticeFile =
|
|
104820
|
+
const dir = join10(deps.configDir, "recordings");
|
|
104821
|
+
const noticeFile = join10(dir, ".notice");
|
|
104518
104822
|
let recorder = null;
|
|
104519
104823
|
let standingOff;
|
|
104520
104824
|
let sessionOff = false;
|
|
@@ -104522,7 +104826,7 @@ function createRecordingRuntime(deps) {
|
|
|
104522
104826
|
if (deps.env.SPACECODE_RECORD?.trim().toLowerCase() === "off") return "SPACECODE_RECORD=off";
|
|
104523
104827
|
let cfg = {};
|
|
104524
104828
|
try {
|
|
104525
|
-
cfg = JSON.parse(await readFile7(
|
|
104829
|
+
cfg = JSON.parse(await readFile7(join10(deps.configDir, "config.json"), "utf8"));
|
|
104526
104830
|
} catch (e) {
|
|
104527
104831
|
if (e.code !== "ENOENT") return `~/.spacecode/config.json is unreadable (${e instanceof Error ? e.message : String(e)}); fix it to record`;
|
|
104528
104832
|
}
|
|
@@ -104530,7 +104834,7 @@ function createRecordingRuntime(deps) {
|
|
|
104530
104834
|
const excludes = Array.isArray(cfg.recording?.exclude) ? cfg.recording.exclude.filter((x2) => typeof x2 === "string") : [];
|
|
104531
104835
|
const hit = excludes.find((p) => matchesExclude(p, deps.projectRoot));
|
|
104532
104836
|
if (hit) return `this folder matches recording.exclude (${hit})`;
|
|
104533
|
-
if (await exists(
|
|
104837
|
+
if (await exists(join10(deps.projectRoot, ".spacecode", "norecord"))) return "this repo has .spacecode/norecord";
|
|
104534
104838
|
return null;
|
|
104535
104839
|
}
|
|
104536
104840
|
async function noticeShown() {
|
|
@@ -104672,7 +104976,7 @@ var init_skills_command = __esm({
|
|
|
104672
104976
|
|
|
104673
104977
|
// src/permission-rules-loader.ts
|
|
104674
104978
|
import { readFile as readFile8 } from "node:fs/promises";
|
|
104675
|
-
import { join as
|
|
104979
|
+
import { join as join11 } from "node:path";
|
|
104676
104980
|
async function readOrNull2(path12) {
|
|
104677
104981
|
try {
|
|
104678
104982
|
return await readFile8(path12, "utf8");
|
|
@@ -104683,7 +104987,7 @@ async function readOrNull2(path12) {
|
|
|
104683
104987
|
}
|
|
104684
104988
|
async function loadPermissionRules(deps) {
|
|
104685
104989
|
const none = (line) => ({ rules: void 0, defaultMode: void 0, statusLines: [line] });
|
|
104686
|
-
const configPath =
|
|
104990
|
+
const configPath = join11(deps.configDir, "imports.json");
|
|
104687
104991
|
try {
|
|
104688
104992
|
const loaded = parseImportsConfig(await readOrNull2(configPath), configPath);
|
|
104689
104993
|
if (loaded.error) return none("permission rules: off (imports.json unreadable)");
|
|
@@ -104692,13 +104996,13 @@ async function loadPermissionRules(deps) {
|
|
|
104692
104996
|
return none(`permission rules: off (imports.json not read: ${err instanceof Error ? err.message : String(err)})`);
|
|
104693
104997
|
}
|
|
104694
104998
|
const lines2 = [];
|
|
104695
|
-
const files = [{ scope: "user", path:
|
|
104999
|
+
const files = [{ scope: "user", path: join11(deps.homeDir, ".claude", "settings.json") }];
|
|
104696
105000
|
try {
|
|
104697
105001
|
const sources2 = await readRepoSources(deps.cwd);
|
|
104698
105002
|
if (sources2[".claude/settings.json"] !== void 0 || sources2[".claude/settings.local.json"] !== void 0) {
|
|
104699
105003
|
const status = await createNodeTrustStore(deps.configDir).repoStatus(deps.cwd, sources2);
|
|
104700
105004
|
if (status === "trusted" || status === "session") {
|
|
104701
|
-
files.push({ scope: "repo", path:
|
|
105005
|
+
files.push({ scope: "repo", path: join11(deps.cwd, ".claude", "settings.json") }, { scope: "local", path: join11(deps.cwd, ".claude", "settings.local.json") });
|
|
104702
105006
|
} else lines2.push(`permission rules: repo settings NOT loaded (${status === "never" ? "marked never trust" : "untrusted repo"})`);
|
|
104703
105007
|
}
|
|
104704
105008
|
} catch (err) {
|
|
@@ -104740,7 +105044,7 @@ var init_permission_rules_loader = __esm({
|
|
|
104740
105044
|
});
|
|
104741
105045
|
|
|
104742
105046
|
// src/command-loader.ts
|
|
104743
|
-
import { join as
|
|
105047
|
+
import { join as join12 } from "node:path";
|
|
104744
105048
|
async function userCommands(deps, lines2) {
|
|
104745
105049
|
try {
|
|
104746
105050
|
const apiKey = await resolveApiKey({ env: deps.env, readFile: deps.readFile, homedir: deps.homedir });
|
|
@@ -104795,7 +105099,7 @@ async function repoCommands(deps, lines2) {
|
|
|
104795
105099
|
}
|
|
104796
105100
|
}
|
|
104797
105101
|
async function loadCommands(deps) {
|
|
104798
|
-
const configPath =
|
|
105102
|
+
const configPath = join12(deps.configDir, "imports.json");
|
|
104799
105103
|
try {
|
|
104800
105104
|
const loaded = parseImportsConfig(await deps.readFile(configPath).catch((err) => {
|
|
104801
105105
|
if (err.code === "ENOENT") return null;
|
|
@@ -104830,7 +105134,7 @@ var init_command_loader = __esm({
|
|
|
104830
105134
|
// src/useReplController.ts
|
|
104831
105135
|
import { readFile as readFile9, writeFile as writeFile6, mkdir as mkdir6 } from "node:fs/promises";
|
|
104832
105136
|
import { homedir as homedir2 } from "node:os";
|
|
104833
|
-
import { join as
|
|
105137
|
+
import { join as join13 } from "node:path";
|
|
104834
105138
|
import { execFile as execFile4 } from "node:child_process";
|
|
104835
105139
|
function useReplController({ repoName: repoName2, yolo: yolo2, mentions: mentionsOpt, sessions, resumeLatest: resumeLatest2, onViewTurns, onViewResume, isEscOwned }) {
|
|
104836
105140
|
const { exit } = use_app_default();
|
|
@@ -104852,8 +105156,13 @@ function useReplController({ repoName: repoName2, yolo: yolo2, mentions: mention
|
|
|
104852
105156
|
return () => clearInterval(timer);
|
|
104853
105157
|
}, [turnStartedAt]);
|
|
104854
105158
|
const projectRoot = (0, import_react30.useMemo)(() => process.cwd(), []);
|
|
105159
|
+
const promptTemplates = (0, import_react30.useCallback)(
|
|
105160
|
+
() => loadPromptTemplates({ env: process.env, readFile: (p) => readFile9(p, "utf-8"), writeFile: (p, d) => writeFile6(p, d, "utf-8"), mkdir: (p) => mkdir6(p, { recursive: true }).then(() => void 0), homedir: homedir2, fetch }),
|
|
105161
|
+
[]
|
|
105162
|
+
);
|
|
104855
105163
|
(0, import_react30.useEffect)(() => {
|
|
104856
105164
|
void loadProjectCard(projectRoot);
|
|
105165
|
+
void promptTemplates();
|
|
104857
105166
|
}, [projectRoot]);
|
|
104858
105167
|
const sessionIdRef = (0, import_react30.useRef)(null);
|
|
104859
105168
|
const sessionCreatedAtRef = (0, import_react30.useRef)(null);
|
|
@@ -104864,7 +105173,7 @@ function useReplController({ repoName: repoName2, yolo: yolo2, mentions: mention
|
|
|
104864
105173
|
const recordingRef = (0, import_react30.useRef)(null);
|
|
104865
105174
|
const recording = () => recordingRef.current ??= createRecordingRuntime({
|
|
104866
105175
|
env: process.env,
|
|
104867
|
-
configDir: process.env.SPACECODE_CONFIG_DIR?.trim() ||
|
|
105176
|
+
configDir: process.env.SPACECODE_CONFIG_DIR?.trim() || join13(homedir2(), ".spacecode"),
|
|
104868
105177
|
projectRoot,
|
|
104869
105178
|
fetch,
|
|
104870
105179
|
baseUrl: backendUrl(process.env),
|
|
@@ -104891,7 +105200,7 @@ function useReplController({ repoName: repoName2, yolo: yolo2, mentions: mention
|
|
|
104891
105200
|
(0, import_react30.useEffect)(() => {
|
|
104892
105201
|
let live2 = true;
|
|
104893
105202
|
loadCommands({
|
|
104894
|
-
configDir: process.env.SPACECODE_CONFIG_DIR?.trim() ||
|
|
105203
|
+
configDir: process.env.SPACECODE_CONFIG_DIR?.trim() || join13(homedir2(), ".spacecode"),
|
|
104895
105204
|
cwd: process.cwd(),
|
|
104896
105205
|
env: process.env,
|
|
104897
105206
|
readFile: (p) => readFile9(p, "utf-8"),
|
|
@@ -105188,7 +105497,7 @@ function useReplController({ repoName: repoName2, yolo: yolo2, mentions: mention
|
|
|
105188
105497
|
return;
|
|
105189
105498
|
}
|
|
105190
105499
|
notice("Compacting conversation\u2026");
|
|
105191
|
-
const summary = await summarizeConversation(history, { apiUrl: apiUrl(), apiKey: apiKey2 });
|
|
105500
|
+
const summary = await summarizeConversation(history, { apiUrl: apiUrl(), apiKey: apiKey2, templates: (await promptTemplates()).templates });
|
|
105192
105501
|
const compacted = buildCompactedHistory(summary.summaryText);
|
|
105193
105502
|
const before = estimateTotalTokens("", history);
|
|
105194
105503
|
const after = estimateTotalTokens("", compacted);
|
|
@@ -105308,7 +105617,7 @@ ${list2.map((c) => ` /${c.name} (${c.scope})${c.description ? ` ${c.descripti
|
|
|
105308
105617
|
cwd: process.cwd(),
|
|
105309
105618
|
gitRoot: gitTopLevel,
|
|
105310
105619
|
importGate: async () => {
|
|
105311
|
-
const configDir = process.env.SPACECODE_CONFIG_DIR?.trim() ||
|
|
105620
|
+
const configDir = process.env.SPACECODE_CONFIG_DIR?.trim() || join13(homedir2(), ".spacecode");
|
|
105312
105621
|
const gate = await importGateStatus({ configDir, cwd: process.cwd(), interactive: Boolean(process.stdin.isTTY) });
|
|
105313
105622
|
const loaded = await loadPermissionRules({ configDir, homeDir: homedir2(), cwd: process.cwd() });
|
|
105314
105623
|
rulesRef.current = loaded.rules;
|
|
@@ -105318,7 +105627,7 @@ ${list2.map((c) => ` /${c.name} (${c.scope})${c.description ? ` ${c.descripti
|
|
|
105318
105627
|
});
|
|
105319
105628
|
profileRef.current = await profilePromiseRef.current;
|
|
105320
105629
|
if (mcpRef.current === null && (profileRef.current?.mcpDefs?.length ?? 0) > 0) {
|
|
105321
|
-
const configDir = process.env.SPACECODE_CONFIG_DIR?.trim() ||
|
|
105630
|
+
const configDir = process.env.SPACECODE_CONFIG_DIR?.trim() || join13(homedir2(), ".spacecode");
|
|
105322
105631
|
const trust = createNodeTrustStore(configDir);
|
|
105323
105632
|
const manager = new McpManager({
|
|
105324
105633
|
defs: profileRef.current.mcpDefs,
|
|
@@ -105328,7 +105637,7 @@ ${list2.map((c) => ` /${c.name} (${c.scope})${c.description ? ` ${c.descripti
|
|
|
105328
105637
|
...rulesRef.current ? { rules: rulesRef.current } : {},
|
|
105329
105638
|
permissions,
|
|
105330
105639
|
confirm: askUser,
|
|
105331
|
-
audit: new FileAuditLog(
|
|
105640
|
+
audit: new FileAuditLog(join13(homedir2(), ".spacecode", "audit.jsonl")),
|
|
105332
105641
|
clientVersion: process.env.SPACECODE_VERSION ?? "0"
|
|
105333
105642
|
});
|
|
105334
105643
|
mcpRef.current = manager;
|
|
@@ -105337,6 +105646,7 @@ ${list2.map((c) => ` /${c.name} (${c.scope})${c.description ? ` ${c.descripti
|
|
|
105337
105646
|
const toolset = createToolset();
|
|
105338
105647
|
toolsetRef.current = toolset;
|
|
105339
105648
|
const projectCard = await loadProjectCard(projectRoot);
|
|
105649
|
+
const prompts = await promptTemplates();
|
|
105340
105650
|
const config = {
|
|
105341
105651
|
apiUrl: apiUrl(),
|
|
105342
105652
|
apiKey,
|
|
@@ -105346,7 +105656,8 @@ ${list2.map((c) => ` /${c.name} (${c.scope})${c.description ? ` ${c.descripti
|
|
|
105346
105656
|
localCwd: projectRoot,
|
|
105347
105657
|
commitGuidance: true,
|
|
105348
105658
|
hasGitHubTools: toolset.hasGitHubTools,
|
|
105349
|
-
...projectCard.text ? { projectCard: projectCard.text } : {}
|
|
105659
|
+
...projectCard.text ? { projectCard: projectCard.text } : {},
|
|
105660
|
+
templates: prompts.templates
|
|
105350
105661
|
}) + (profileRef.current?.promptSection ?? ""),
|
|
105351
105662
|
tools: toolset.tools,
|
|
105352
105663
|
maxTurns: 100,
|
|
@@ -105458,6 +105769,7 @@ var init_useReplController = __esm({
|
|
|
105458
105769
|
init_session_commands();
|
|
105459
105770
|
init_local_toolset();
|
|
105460
105771
|
init_project_card_runtime();
|
|
105772
|
+
init_prompt_runtime();
|
|
105461
105773
|
init_shell_turn();
|
|
105462
105774
|
init_node_mentions();
|
|
105463
105775
|
init_api_key();
|