claude-dev-env 8.30.0 → 8.31.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/.agents/skills/windows-scheduled-task/SKILL.md +9 -5
- package/hooks/hooks_constants/working_style_prompt_constants.py +11 -6
- package/hooks/session/test_working_style_prompt.py +16 -1
- package/hooks/session/working_style_prompt.py +3 -2
- package/package.json +1 -1
- package/scripts/Install-SweepEmptyDirs.ps1 +2 -1
- package/scripts/tests/test_install_sweep_empty_dirs.py +42 -0
|
@@ -39,6 +39,7 @@ prove the task by the artifact it changes.
|
|
|
39
39
|
- `LastTaskResult: 0` from a run that took the idle branch says nothing about the branch that acts.
|
|
40
40
|
- A `#Requires -RunAsAdministrator` line pasted at a prompt checks nothing. It applies only to a script file.
|
|
41
41
|
- An elevated window opens in `C:\WINDOWS\system32`. A prompt in the user's home folder is usually unelevated.
|
|
42
|
+
- An Interactive task that starts `pwsh.exe -WindowStyle Hidden` still flashes a console window on the signed-in desktop. Windows draws the console before PowerShell reads the flag. `conhost.exe --headless` in front of the executable starts it with no window.
|
|
42
43
|
|
|
43
44
|
## When this applies
|
|
44
45
|
|
|
@@ -49,7 +50,7 @@ module. Register the task in an elevated shell when the task must run while the
|
|
|
49
50
|
|
|
50
51
|
1. Resolve every executable in the action with `Get-Command <name>` and read `.Source`.
|
|
51
52
|
2. Read `files[]` in `~/.claude/.claude-dev-env-manifest.json` and pick a directory that list omits.
|
|
52
|
-
3. Build the action with the
|
|
53
|
+
3. Build the action with `conhost.exe --headless` as the executable, followed by the absolute path of the program it starts.
|
|
53
54
|
4. Build a `-Once` trigger with a repetition interval and no duration, then clear the duration on the trigger object.
|
|
54
55
|
5. Build the settings set.
|
|
55
56
|
6. Register with an S4U principal, catch the registration failure, and register with an Interactive principal.
|
|
@@ -83,18 +84,21 @@ try {
|
|
|
83
84
|
```
|
|
84
85
|
|
|
85
86
|
S4U runs the task with no window whether or not the user is signed in, and its registration needs an
|
|
86
|
-
elevated shell. The Interactive principal
|
|
87
|
-
|
|
87
|
+
elevated shell. The Interactive principal runs the task on the signed-in desktop, so its action goes
|
|
88
|
+
through `conhost.exe --headless` to stay windowless. Report `$PrincipalKind` so the operator knows
|
|
89
|
+
which one the task holds.
|
|
88
90
|
|
|
89
91
|
## Absolute paths in the action
|
|
90
92
|
|
|
91
93
|
```powershell
|
|
94
|
+
$ConhostPath = Join-Path -Path $env:SystemRoot -ChildPath 'System32\conhost.exe'
|
|
92
95
|
$PwshPath = (Get-Command pwsh).Source
|
|
93
|
-
$Action = New-ScheduledTaskAction -Execute $
|
|
96
|
+
$Action = New-ScheduledTaskAction -Execute $ConhostPath -Argument "--headless ""$PwshPath"" -NoProfile -File ""$ScriptPath"""
|
|
94
97
|
```
|
|
95
98
|
|
|
96
99
|
Resolve each executable at registration time and store the absolute path in the action. Give the
|
|
97
|
-
script an absolute path too.
|
|
100
|
+
script an absolute path too. The same `--headless` front works for any console program, such as
|
|
101
|
+
`python.exe` or `cmd.exe`.
|
|
98
102
|
|
|
99
103
|
## Settings
|
|
100
104
|
|
|
@@ -16,10 +16,15 @@ WORKING_STYLE_PROMPT = (
|
|
|
16
16
|
"Keep disclaimers and caveats short while giving "
|
|
17
17
|
"the main answer most of the response. Give a high-level explanation by default "
|
|
18
18
|
"and provide depth when the request calls for it. "
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"
|
|
19
|
+
"On a typed request, state your next action in one sentence before the first "
|
|
20
|
+
"tool call. "
|
|
21
|
+
"Finish with the outcome in the first sentence. "
|
|
22
|
+
"Send the user only what they must act on or need to know. When a background "
|
|
23
|
+
"event, such as a task notification, an agent message, or a scheduled wake, "
|
|
24
|
+
"starts a turn and nothing in it needs the user, end the turn with no text. A "
|
|
25
|
+
"report that a fix is done carries three lines: the fix acknowledged, what "
|
|
26
|
+
"changed, and the proof that it works. Put the rest of the detail in the pull "
|
|
27
|
+
"request or a linked file. "
|
|
23
28
|
"Match written-document length to the task. Cover the substance and keep every "
|
|
24
29
|
"section, summary, and phrase useful. "
|
|
25
30
|
"Deliver the requested work at its intended scope. Make routine judgment calls "
|
|
@@ -34,7 +39,7 @@ WORKING_STYLE_PROMPT = (
|
|
|
34
39
|
"when the ambiguity changes the outcome, scope, audience, format, or risk. Use a "
|
|
35
40
|
"clearly stated low-risk assumption when the intended result remains stable. "
|
|
36
41
|
"Pause for the user's choice before making a high-impact decision. "
|
|
37
|
-
"Use current, immediately relevant context.
|
|
38
|
-
"
|
|
42
|
+
"Use current, immediately relevant context. "
|
|
43
|
+
"Use full terms and specific names for repository work. Keep all "
|
|
39
44
|
"text concise, clear, direct, and useful."
|
|
40
45
|
)
|
|
@@ -50,11 +50,26 @@ class TestWorkingStylePrompt:
|
|
|
50
50
|
assert "update-in-place continuity, and sharing" in prompt_text
|
|
51
51
|
assert "Apply ~/.claude/rules/asd-ste100-language.md for user-facing word choice" in prompt_text
|
|
52
52
|
assert "Use current, immediately relevant context." in prompt_text
|
|
53
|
-
assert "Name each action, fact, reason, and outcome." in prompt_text
|
|
54
53
|
assert "Use full terms and specific names for repository work." in prompt_text
|
|
55
54
|
assert "When a request has multiple reasonable interpretations" in prompt_text
|
|
56
55
|
assert "Ask one focused clarification question" in prompt_text
|
|
57
56
|
assert "Pause for the user's choice before making a high-impact decision." in prompt_text
|
|
58
57
|
|
|
58
|
+
def test_prompt_limits_replies_to_what_the_user_must_act_on_or_know(self) -> None:
|
|
59
|
+
assert "Send the user only what they must act on or need to know." in WORKING_STYLE_PROMPT
|
|
60
|
+
assert "starts a turn and nothing in it needs the user, end the turn with no text." in WORKING_STYLE_PROMPT
|
|
61
|
+
assert "On a typed request, state your next action in one sentence" in WORKING_STYLE_PROMPT
|
|
62
|
+
assert "Before your first tool call, state your next action" not in WORKING_STYLE_PROMPT
|
|
63
|
+
assert (
|
|
64
|
+
"A report that a fix is done carries three lines: the fix acknowledged, "
|
|
65
|
+
"what changed, and the proof that it works."
|
|
66
|
+
) in WORKING_STYLE_PROMPT
|
|
67
|
+
assert "Put the rest of the detail in the pull request or a linked file." in WORKING_STYLE_PROMPT
|
|
68
|
+
|
|
69
|
+
def test_prompt_drops_the_clauses_that_invite_surplus_detail(self) -> None:
|
|
70
|
+
assert "supporting detail for readers who want it" not in WORKING_STYLE_PROMPT
|
|
71
|
+
assert "give brief updates when you find important information" not in WORKING_STYLE_PROMPT
|
|
72
|
+
assert "Name each action, fact, reason, and outcome." not in WORKING_STYLE_PROMPT
|
|
73
|
+
|
|
59
74
|
def test_build_session_directive_returns_the_shared_constant(self) -> None:
|
|
60
75
|
assert starter.build_session_directive() == WORKING_STYLE_PROMPT
|
|
@@ -4,8 +4,9 @@
|
|
|
4
4
|
At session start this hook emits an ``additionalContext`` block carrying a fixed
|
|
5
5
|
working-style prompt: use ELI5 for the beginner presentation envelope, follow
|
|
6
6
|
``~/.claude/rules/asd-ste100-language.md`` for sentence prose, keep a running
|
|
7
|
-
ledger, narrate before the first tool call
|
|
8
|
-
the
|
|
7
|
+
ledger, narrate before the first tool call on a typed request, lead with the
|
|
8
|
+
outcome, send only what the user must act on or know, stay silent on a
|
|
9
|
+
background-event turn that needs nothing, and stay at the asked scope.
|
|
9
10
|
The hook writes nothing and runs no tools itself.
|
|
10
11
|
"""
|
|
11
12
|
|
package/package.json
CHANGED
|
@@ -99,7 +99,8 @@ if (-not $?) {
|
|
|
99
99
|
$Target = (Resolve-Path $Target).Path
|
|
100
100
|
$Target = [System.IO.Path]::TrimEndingDirectorySeparator($Target)
|
|
101
101
|
|
|
102
|
-
$
|
|
102
|
+
$ConhostPath = Join-Path -Path $env:SystemRoot -ChildPath 'System32\conhost.exe'
|
|
103
|
+
$Action = New-ScheduledTaskAction -Execute $ConhostPath -Argument "--headless ""$PythonPath"" ""$ScriptPath"" --once --age $AgeSeconds ""$Target"""
|
|
103
104
|
$Trigger = New-ScheduledTaskTrigger -Once -At $StartAt -RepetitionInterval (New-TimeSpan -Minutes $IntervalMinutes) -RepetitionDuration (New-TimeSpan -Days 31)
|
|
104
105
|
$Settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -StartWhenAvailable
|
|
105
106
|
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""Specifications for the scheduled task Install-SweepEmptyDirs.ps1 registers.
|
|
2
|
+
|
|
3
|
+
A task that starts a console program straight from Task Scheduler draws a
|
|
4
|
+
console window on the signed-in desktop at every run. The registered action
|
|
5
|
+
starts the program through conhost.exe --headless so no window appears.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import re
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
|
|
13
|
+
_INSTALLER_PATH = Path(__file__).resolve().parents[1] / "Install-SweepEmptyDirs.ps1"
|
|
14
|
+
_UTF8_ENCODING = "utf-8"
|
|
15
|
+
_ACTION_PATTERN = re.compile(
|
|
16
|
+
r"^\$Action = New-ScheduledTaskAction -Execute (\$\w+) -Argument (.+)$",
|
|
17
|
+
re.MULTILINE,
|
|
18
|
+
)
|
|
19
|
+
_CONHOST_ASSIGNMENT = (
|
|
20
|
+
"$ConhostPath = Join-Path -Path $env:SystemRoot -ChildPath 'System32\\conhost.exe'"
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _registered_action() -> tuple[str, str]:
|
|
25
|
+
installer_text = _INSTALLER_PATH.read_text(encoding=_UTF8_ENCODING)
|
|
26
|
+
all_actions = _ACTION_PATTERN.findall(installer_text)
|
|
27
|
+
assert len(all_actions) == 1, all_actions
|
|
28
|
+
return all_actions[0]
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def test_should_start_the_task_through_conhost() -> None:
|
|
32
|
+
installer_text = _INSTALLER_PATH.read_text(encoding=_UTF8_ENCODING)
|
|
33
|
+
executable_variable, _ = _registered_action()
|
|
34
|
+
|
|
35
|
+
assert executable_variable == "$ConhostPath"
|
|
36
|
+
assert _CONHOST_ASSIGNMENT in installer_text
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def test_should_pass_headless_before_the_python_program() -> None:
|
|
40
|
+
_, argument_text = _registered_action()
|
|
41
|
+
|
|
42
|
+
assert argument_text.startswith('"--headless ""$PythonPath"" ""$ScriptPath""')
|