@tyhld/conductor 0.12.65 → 0.12.67
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/headless.js +70 -20
- package/package.json +1 -1
- package/sales-template/settings.json +6 -5
- package/scripts/update-guard.sh +4 -0
package/dist/headless.js
CHANGED
|
@@ -129,35 +129,51 @@ export function loadAndClearLegacyActiveJob() {
|
|
|
129
129
|
}
|
|
130
130
|
}
|
|
131
131
|
/**
|
|
132
|
-
*
|
|
133
|
-
* site, machine, workDir, gitOrigin
|
|
134
|
-
*
|
|
132
|
+
* 手元の記録が自分(この中継)のものか照合する(Fail Closed)。
|
|
133
|
+
* site, machine, workDir, gitOrigin の4項目を比べる。
|
|
134
|
+
*
|
|
135
|
+
* ★Fail Closed: 確認できない項目(記録に無い・今の値が取れない)は
|
|
136
|
+
* 不一致と同じ扱いにする。確認できた項目がすべて一致した場合だけ null を返す。
|
|
135
137
|
*
|
|
136
138
|
* ★commandId は「この便が中央でまだ sent か」の確認(ネットワーク照合)で別に行う。
|
|
137
139
|
* ここではローカルの所有者照合のみ。
|
|
138
140
|
*/
|
|
139
141
|
export function validateActiveJobOwnership(rec, cfg) {
|
|
140
142
|
const mismatches = [];
|
|
141
|
-
|
|
143
|
+
// site — 記録に無ければ確認不能
|
|
144
|
+
if (rec.site === undefined) {
|
|
145
|
+
mismatches.push('site: 記録に無い(確認不能)');
|
|
146
|
+
}
|
|
147
|
+
else if (rec.site !== cfg.site) {
|
|
142
148
|
mismatches.push(`site: 記録=${rec.site} 自分=${cfg.site}`);
|
|
143
149
|
}
|
|
144
|
-
|
|
150
|
+
// machine — 記録に無ければ確認不能
|
|
151
|
+
if (rec.machine === undefined) {
|
|
152
|
+
mismatches.push('machine: 記録に無い(確認不能)');
|
|
153
|
+
}
|
|
154
|
+
else if (rec.machine !== cfg.machine) {
|
|
145
155
|
mismatches.push(`machine: 記録=${rec.machine} 自分=${cfg.machine}`);
|
|
146
156
|
}
|
|
147
|
-
|
|
157
|
+
// workDir — 記録に無ければ確認不能
|
|
158
|
+
if (rec.workDir === undefined) {
|
|
159
|
+
mismatches.push('workDir: 記録に無い(確認不能)');
|
|
160
|
+
}
|
|
161
|
+
else if (rec.workDir !== cfg.workDir) {
|
|
148
162
|
mismatches.push(`workDir: 記録=${rec.workDir} 自分=${cfg.workDir}`);
|
|
149
163
|
}
|
|
150
|
-
//
|
|
151
|
-
if (rec.gitOrigin
|
|
164
|
+
// gitOrigin — 記録に無い or 今の値が取れない → 確認不能
|
|
165
|
+
if (rec.gitOrigin === undefined) {
|
|
166
|
+
mismatches.push('gitOrigin: 記録に無い(確認不能)');
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
152
169
|
const currentOrigin = resolveGitOrigin(cfg.workDir);
|
|
153
|
-
if (currentOrigin
|
|
170
|
+
if (currentOrigin === null) {
|
|
171
|
+
mismatches.push('gitOrigin: 今のリポの origin を取得できない(確認不能)');
|
|
172
|
+
}
|
|
173
|
+
else if (rec.gitOrigin !== currentOrigin) {
|
|
154
174
|
mismatches.push(`gitOrigin: 記録=${rec.gitOrigin} 自分=${currentOrigin}`);
|
|
155
175
|
}
|
|
156
176
|
}
|
|
157
|
-
// 照合項目がそろわない古い記録は安全に拾えない。
|
|
158
|
-
if (rec.site === undefined || rec.machine === undefined || rec.workDir === undefined) {
|
|
159
|
-
mismatches.push('照合項目が不足(古い記録)');
|
|
160
|
-
}
|
|
161
177
|
return mismatches.length > 0 ? mismatches.join(', ') : null;
|
|
162
178
|
}
|
|
163
179
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -755,25 +771,38 @@ export async function restoreHeadlessOrphans(cfg, state) {
|
|
|
755
771
|
log(`site=${cfg.site} 古い共有の active-job.json を消しました(現場ごとの記録を優先)`);
|
|
756
772
|
}
|
|
757
773
|
if (saved !== null) {
|
|
758
|
-
//
|
|
774
|
+
// ★所有者照合(Fail Closed): site, machine, workDir, gitOrigin がすべて確認でき一致しなければ再開しない
|
|
759
775
|
const mismatch = validateActiveJobOwnership(saved, cfg);
|
|
760
776
|
if (mismatch !== null) {
|
|
761
|
-
log(`WARN site=${cfg.site} id=${saved.commandId}
|
|
777
|
+
log(`WARN site=${cfg.site} id=${saved.commandId} 手元の記録は自分のものと確認できない → 再開しない(${mismatch})`);
|
|
762
778
|
await sendCommandEvents(cfg, saved.commandId, [{
|
|
763
779
|
type: 'error',
|
|
764
|
-
text:
|
|
780
|
+
text: `所有者照合で再開しない(${mismatch})`.slice(0, EVENT_TEXT_MAX),
|
|
765
781
|
at: new Date().toISOString(),
|
|
766
782
|
attempt: saved.attempt,
|
|
767
783
|
}]);
|
|
768
784
|
return;
|
|
769
785
|
}
|
|
770
|
-
// ★便ID
|
|
786
|
+
// ★便IDの照合(Fail Closed): 中央でまだ sent のまま残っている便か確かめる。
|
|
787
|
+
// 確かめられなかった(null)ときも再開しない。ただし記録を戻して次の tick で再試行する。
|
|
771
788
|
const centralStatus = await fetchCommandStatus(cfg, saved.commandId);
|
|
772
|
-
if (centralStatus
|
|
773
|
-
log(`WARN site=${cfg.site} id=${saved.commandId}
|
|
789
|
+
if (centralStatus === null) {
|
|
790
|
+
log(`WARN site=${cfg.site} id=${saved.commandId} 中央の状態を確かめられない → 再開しない(次の tick で再試行)`);
|
|
791
|
+
// ★記録を戻す: 次の tick でもう一度確かめられるようにする(便を黙って捨てない)
|
|
792
|
+
saveActiveJob(cfg.site, saved);
|
|
793
|
+
await sendCommandEvents(cfg, saved.commandId, [{
|
|
794
|
+
type: 'error',
|
|
795
|
+
text: '中央の便の状態を確かめられない(ネットワーク障害等)→ 再開しない(次の tick で再試行)'.slice(0, EVENT_TEXT_MAX),
|
|
796
|
+
at: new Date().toISOString(),
|
|
797
|
+
attempt: saved.attempt,
|
|
798
|
+
}]);
|
|
799
|
+
return;
|
|
800
|
+
}
|
|
801
|
+
if (centralStatus !== 'sent') {
|
|
802
|
+
log(`WARN site=${cfg.site} id=${saved.commandId} 中央で ${centralStatus} → 再開しない`);
|
|
774
803
|
await sendCommandEvents(cfg, saved.commandId, [{
|
|
775
804
|
type: 'error',
|
|
776
|
-
text:
|
|
805
|
+
text: `中央の便の状態が sent ではない(${centralStatus})→ 再開しない`.slice(0, EVENT_TEXT_MAX),
|
|
777
806
|
at: new Date().toISOString(),
|
|
778
807
|
attempt: saved.attempt,
|
|
779
808
|
}]);
|
|
@@ -813,10 +842,31 @@ export async function restoreHeadlessOrphans(cfg, state) {
|
|
|
813
842
|
return;
|
|
814
843
|
}
|
|
815
844
|
// ── 経路2: 中央から孤児を拾う(PC 再起動後) ──
|
|
845
|
+
// ★Fail Closed: 中央の孤児には machine/workDir/gitOrigin が無い。
|
|
846
|
+
// 手元の記録(active-job ファイル)が無い場合、所有者照合で確認不能 → 再開しない。
|
|
847
|
+
// 手元の記録があれば経路1で拾われているので、経路2に来る時点で手元の記録は無い。
|
|
816
848
|
const orphans = await fetchOrphans(cfg);
|
|
817
849
|
const pick = selectOrphanToRestore(orphans, null);
|
|
818
850
|
if (pick === null)
|
|
819
851
|
return;
|
|
852
|
+
// ★所有者照合(Fail Closed): 中央の孤児は所有者情報を持たないため確認不能。
|
|
853
|
+
// 手元の記録があれば経路1で処理済み。ここに来る=手元の記録が無い=確認不能。
|
|
854
|
+
const orphanAsRecord = {
|
|
855
|
+
commandId: pick.id, body: pick.body, sessionId: '', attempt: 0,
|
|
856
|
+
startedAt: 0, site: pick.site,
|
|
857
|
+
// machine, workDir, gitOrigin は中央に無い → undefined → 確認不能
|
|
858
|
+
};
|
|
859
|
+
const orphanMismatch = validateActiveJobOwnership(orphanAsRecord, cfg);
|
|
860
|
+
if (orphanMismatch !== null) {
|
|
861
|
+
log(`WARN site=${cfg.site} id=${pick.id} 中央の孤児は所有者を確認できない → 再開しない(${orphanMismatch})`);
|
|
862
|
+
await sendCommandEvents(cfg, pick.id, [{
|
|
863
|
+
type: 'error',
|
|
864
|
+
text: `中央の孤児の所有者照合で再開しない(${orphanMismatch})`.slice(0, EVENT_TEXT_MAX),
|
|
865
|
+
at: new Date().toISOString(),
|
|
866
|
+
attempt: 0,
|
|
867
|
+
}]);
|
|
868
|
+
return;
|
|
869
|
+
}
|
|
820
870
|
const attempt = (state.attempts.get(pick.id) ?? 0) + 1;
|
|
821
871
|
state.attempts.set(pick.id, attempt);
|
|
822
872
|
if (attempt > HEADLESS_MAX_ATTEMPTS) {
|
package/package.json
CHANGED
|
@@ -14,9 +14,10 @@
|
|
|
14
14
|
"Bash(git push --force:*)",
|
|
15
15
|
"Bash(git push -f:*)",
|
|
16
16
|
"Bash(git push --force-with-lease:*)",
|
|
17
|
-
"Bash(git push * --force
|
|
18
|
-
"Bash(git push * -f
|
|
19
|
-
"Bash(git push * --force-with-lease
|
|
17
|
+
"Bash(git push * --force)",
|
|
18
|
+
"Bash(git push * -f)",
|
|
19
|
+
"Bash(git push * --force-with-lease)",
|
|
20
|
+
"Bash(git push * +*)",
|
|
20
21
|
"Bash(rm -rf:*)",
|
|
21
22
|
"Bash(rm -fr:*)",
|
|
22
23
|
"Bash(rm -r -f:*)",
|
|
@@ -45,8 +46,8 @@
|
|
|
45
46
|
"Bash(*TRUNCATE*)",
|
|
46
47
|
"Bash(*rest/v1/rpc/exec_sql*)",
|
|
47
48
|
"Bash(cat .env:*)",
|
|
48
|
-
"Bash(cat .env
|
|
49
|
-
"Bash(cat *.env
|
|
49
|
+
"Bash(cat .env.*)",
|
|
50
|
+
"Bash(cat *.env)",
|
|
50
51
|
"Bash(printenv:*)",
|
|
51
52
|
"Bash(echo $DATABASE_URL:*)",
|
|
52
53
|
"Bash(echo $DIRECT_URL:*)",
|
package/scripts/update-guard.sh
CHANGED
|
@@ -999,6 +999,10 @@ RETIRED_DENY = frozenset({
|
|
|
999
999
|
"Read(**/.config/gh/hosts.yml)", "Read(**/.npmrc)", "Read(**/*.env)", "Read(**/*.pem)",
|
|
1000
1000
|
"Read(**/*.key)", "Read(**/credentials.json)", "Read(**/.credentials.json)",
|
|
1001
1001
|
"Read(**/auth.json)", "Read(**/*login.json)",
|
|
1002
|
+
# ★便 07ee11a2: * と :* を混ぜた書き方は Claude Code が * をリテラル扱いして何も止めない。
|
|
1003
|
+
# 正しい形(* をワイルドカードとして展開)を正本に足したので、壊れた旧形を退役する。
|
|
1004
|
+
"Bash(git push * --force:*)", "Bash(git push * -f:*)", "Bash(git push * --force-with-lease:*)",
|
|
1005
|
+
"Bash(cat .env.*:*)", "Bash(cat *.env:*)",
|
|
1002
1006
|
})
|
|
1003
1007
|
retire_hit = [r for r in cur if r in RETIRED_DENY]
|
|
1004
1008
|
if retire_hit:
|