@xdxer/dingtalk-agent 0.1.5-beta.10 → 0.1.5-beta.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,22 @@
2
2
 
3
3
  All notable changes to `@xdxer/dingtalk-agent` are documented here. The project follows semantic versioning; prerelease entries describe release candidates and do not imply that Live canaries or registry publication have completed.
4
4
 
5
+ ## 0.1.5-beta.12 - 2026-07-25
6
+
7
+ One unreachable path made reachable: the completion predicate a scheduled run is judged against now travels to that run as a managed artifact, instead of being a name the run holds with no body behind it. Ships on the `beta` dist-tag; `latest` stays at 0.1.4. Merged as PR #57.
8
+
9
+ ### Added
10
+
11
+ - **The completion-predicate registry now actually reaches the runtime (closes #46).** #40 shipped a registry whose id was referenced by both the declaration and the autopilot description, and claimed the manifest travelled into the runtime with `skill-push`. It did not: `skill-push` uploads only the skill directory, the target runtime is not guaranteed to carry `multica_ext.py`, and nothing read the id back — so a run held an id and no predicate body, and "the runtime reads the same registry" was an unreachable path. The registry is now a **managed runtime artifact**: `dta deploy` projects the manifest registry into `predicate-registry@1` (`src/predicate-registry.ts` is the only writer and the only parser) and pushes it as `<owner-skill>/references/predicate-registry.json` through the existing skill-push chain — no second transport. Owner resolution is one shared rule (`dta-basic-behavior` if managed, else the lexicographically first managed skill), so the injector and the wake prompt cannot point at different files. The projection hash therefore enters the skill tree hash → deployment hash → the deployment receipt's `predicateRegistry` (skill/path/hash/ids/schedules), and drift shows up in the existing skill-hash readback. Per-run consumption is wired in the wake description: alongside `[dta-completion-predicate] <id>` it now carries `[dta-predicate-registry] <skill>/references/predicate-registry.json` and the instruction that a run which cannot resolve the predicate — file missing, hash disagreeing with content, id not delivered — may not use completion wording; the basic-behavior completion gate states the same rule as step 5 (0.15.0). `multica_ext.py predicate-resolve` gains `--registry` beside `--manifest` (mirroring the hash check in Python, so both languages compute the same digest or fail loudly; ops skill 0.5.0, compose 0.16.5). A managed projection never overwrites an authored file at that path, and a project that declares a registry with no skill to carry it is refused rather than deployed with an unreadable predicate. Scenario #54 proves reachability the way #46 asked: after a real deploy to the fake provider, the projection is read back **out of the pushed payload**, a second process resolves the predicate body from those bytes alone (no manifest, no provider CLI, no credentials, cwd outside the project), Python agrees on the hash, tamper/unregistered-id/missing-file all exit non-zero, and changing one word of a predicate description moves both the projection hash and the deployment hash. #74 pins the projection contract itself in the core tier.
12
+
13
+ ## 0.1.5-beta.11 - 2026-07-25
14
+
15
+ A one-fix release, and the fix is a boundary that was being checked with the wrong instrument: string comparison cannot prove that a directory belongs to the host. The state-directory contract now has exactly one owner, and both the receipt store and the candidate store read it instead of keeping private copies. Ships on the `beta` dist-tag; `latest` stays at 0.1.4. Merged as PR #54.
16
+
17
+ ### Fixed
18
+
19
+ - **A symlink inside the agent root let prepared no-op receipts be written outside it (closes #52).** #47 correctly widened the prepared write boundary from the literal `.dingtalk-agent` to "anywhere in the agent root", but it compared `resolve()` strings only. A directory symlink inside the root pointing outside it therefore passed containment, and `mkdirSync`/the atomic write then followed that link: `recordMemoryNoop(root, claim, {stateDir: '.state-link'})` returned a lexical path under the root while `realpath` landed in a directory the host does not own — which is exactly the deployment fact #42 rests authenticity on ("the state directory is host-owned"), so a lexical check can prove neither ownership nor containment. The stateDir contract now has a single owner (`src/state-dir.ts`): lexical containment, stateDir may not equal the root (the bindings "separate private directory" rule), and the realpath of the existing prefix — plus a re-check after the directory is created, covering nested segments and swap races — must stay inside the agent root; a dangling symlink fails closed instead of surfacing as `ENOENT`. `loadAgentBindings` and the prepared candidate store read that same contract instead of keeping private copies (candidate writes were escapable the same way). Legitimate `.agent-private` setups keep issuing and tracing; `../outside-root`, a root-internal symlink to the outside (as stateDir or as its nested `memory/`), and `stateDir='.'` are all refused, and scenario #75 asserts the outside directories stay receipt-free.
20
+
5
21
  ## 0.1.5-beta.10 - 2026-07-25
6
22
 
7
23
  The registry-and-receipts wave: every "the declaration says X" now has a reader on the other side that can prove or refute it. Completion predicates became referenced registry entries with a readback-verified marker; the memory save-decision leaves a typed, forgery-hardened trace; and three review rounds on this very wave (#35/#38/#39, #42, #45/#46/#47) were folded back in before shipping. Ships on the `beta` dist-tag; `latest` stays at 0.1.4. Merged as PRs #34, #36, #37, #41, #43, #44, #48, #49.
@@ -2198,6 +2198,12 @@ function printMulticaDeployment(out) {
2198
2198
  if (out.rebind?.fromRuntimeId) {
2199
2199
  console.log(` rebind: ${out.rebind.fromRuntimeId} -> ${out.rebind.toRuntimeId}`);
2200
2200
  }
2201
+ // 交付了哪份判据要看得见(issue #46):运行拍读的就是这个文件,operator 得能对账。
2202
+ if (out.predicateRegistry) {
2203
+ const reg = out.predicateRegistry;
2204
+ console.log(` predicate registry: ${reg.skill}/${reg.path} (${reg.hash.slice(0, 12)})`);
2205
+ console.log(` ids: ${reg.ids.join(', ') || '-'} schedules: ${reg.schedules.join(', ') || '-'}`);
2206
+ }
2201
2207
  const smoke = out.smoke || out.receipt?.smoke;
2202
2208
  if (smoke && smoke.status && smoke.status !== 'not-run') {
2203
2209
  const classified = smoke.classification ? ` (${smoke.classification})` : '';